Spring单实例、多线程安全、事务解析
原文:http://blog.csdn.net/c289054531/article/details/9196053
引言:
2。将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。
Spring使用ThreadLocal解决线程安全问题:
- <span style="font-family:SimSun;font-size:14px;">public class SqlConnection {
 - //①使用ThreadLocal保存Connection变量
 - privatestatic ThreadLocal <Connection>connThreadLocal = newThreadLocal<Connection>();
 - publicstatic Connection getConnection() {
 - // ②如果connThreadLocal没有本线程对应的Connection创建一个新的Connection,
 - // 并将其保存到线程本地变量中。
 - if (connThreadLocal.get() == null) {
 - Connection conn = getConnection();
 - connThreadLocal.set(conn);
 - return conn;
 - } else {
 - return connThreadLocal.get();
 - // ③直接返回线程本地变量
 - }
 - }
 - public voidaddTopic() {
 - // ④从ThreadLocal中获取线程对应的Connection
 - try {
 - Statement stat = getConnection().createStatement();
 - } catch (SQLException e) {
 - e.printStackTrace();
 - }
 - }
 - }</span>
 
事务管理器:
事务传播行为:
- <span style="font-family:SimSun;font-size:14px;">@Service( "userService")
 - public class UserService extends BaseService {
 - @Autowired
 - private JdbcTemplate jdbcTemplate;
 - @Autowired
 - private ScoreService scoreService;
 - public void logon(String userName) {
 - updateLastLogonTime(userName);
 - scoreService.addScore(userName, 20);
 - }
 - public void updateLastLogonTime(String userName) {
 - String sql = "UPDATE t_user u SET u.last_logon_time = ? WHERE user_name =?";
 - jdbcTemplate.update(sql, System. currentTimeMillis(), userName);
 - }
 - public static void main(String[] args) {
 - ApplicationContext ctx = new ClassPathXmlApplicationContext("com/baobaotao/nestcall/applicatonContext.xml" );
 - UserService service = (UserService) ctx.getBean("userService" );
 - service.logon( "tom");
 - }
 - }
 - @Service( "scoreUserService" )
 - public class ScoreService extends BaseService{
 - @Autowired
 - private JdbcTemplate jdbcTemplate;
 - public void addScore(String userName, int toAdd) {
 - String sql = "UPDATE t_user u SET u.score = u.score + ? WHERE user_name =?";
 - jdbcTemplate.update(sql, toAdd, userName);
 - }
 - }</span>
 
多线程中事务传播的困惑:
- <span style="font-family:SimSun;font-size:14px;">@Service( "userService")
 - public class UserService extends BaseService {
 - @Autowired
 - private JdbcTemplate jdbcTemplate;
 - @Autowired
 - private ScoreService scoreService;
 - public void logon(String userName) {
 - updateLastLogonTime(userName);
 - Thread myThread = new MyThread(this.scoreService , userName, 20);//使用一个新线程运行
 - myThread .start();
 - }
 - public void updateLastLogonTime(String userName) {
 - String sql = "UPDATE t_user u SET u.last_logon_time = ? WHERE user_name =?";
 - jdbcTemplate.update(sql, System. currentTimeMillis(), userName);
 - }
 - private class MyThread extends Thread {
 - private ScoreService scoreService;
 - private String userName;
 - private int toAdd;
 - private MyThread(ScoreService scoreService, String userName, int toAdd) {
 - this. scoreService = scoreService;
 - this. userName = userName;
 - this. toAdd = toAdd;
 - }
 - public void run() {
 - scoreService.addScore( userName, toAdd);
 - }
 - }
 - public static void main(String[] args) {
 - ApplicationContext ctx = new ClassPathXmlApplicationContext("com/baobaotao/multithread/applicatonContext.xml" );
 - UserService service = (UserService) ctx.getBean("userService" );
 - service.logon( "tom");
 - }
 - }</span>
 
底层数据库连接Connection访问问题
- <span style="font-family:SimSun;font-size:14px;">@Service( "jdbcUserService" )
 - public class JdbcUserService {
 - @Autowired
 - private JdbcTemplate jdbcTemplate;
 - @Transactional
 - public void logon(String userName) {
 - try {
 - Connection conn = jdbcTemplate.getDataSource().getConnection();
 - String sql = "UPDATE t_user SET last_logon_time=? WHERE user_name =?";
 - jdbcTemplate.update(sql, System. currentTimeMillis(), userName);
 - } catch (Exception e) {
 - e.printStackTrace();
 - }
 - }
 - public static void asynchrLogon(JdbcUserService userService, String userName) {
 - UserServiceRunner runner = new UserServiceRunner(userService, userName);
 - runner.start();
 - }
 - public static void reportConn(BasicDataSource basicDataSource) {
 - System. out.println( "连接数[active:idle]-[" +
 - basicDataSource.getNumActive()+":" +basicDataSource.getNumIdle()+ "]");
 - }
 - private static class UserServiceRunner extends Thread {
 - private JdbcUserService userService;
 - private String userName;
 - public UserServiceRunner(JdbcUserService userService, String userName) {
 - this. userService = userService;
 - this. userName = userName;
 - }
 - public void run() {
 - userService.logon( userName);
 - }
 - }
 - public static void main(String[] args) {
 - ApplicationContext ctx = new ClassPathXmlApplicationContext("com/baobaotao/connleak/applicatonContext.xml" );
 - JdbcUserService userService = (JdbcUserService) ctx.getBean("jdbcUserService" );
 - JdbcUserService. asynchrLogon(userService, "tom");
 - }
 - }</span>
 
多线程一定要与事务挂钩么?
结论:
- Spring中DAO和Service都是以单实例的bean形式存在,Spring通过ThreadLocal类将有状态的变量(例如数据库连接Connection)本地线程化,从而做到多线程状况下的安全。在一次请求响应的处理线程中, 该线程贯通展示、服务、数据持久化三层,通过ThreadLocal使得所有关联的对象引用到的都是同一个变量。
 - 在事务属性为REQUIRED时,在相同线程中进行相互嵌套调用的事务方法工作于相同的事务中。如果互相嵌套调用的事务方法工作在不同线程中,则不同线程下的事务方法工作在独立的事务中。
 - 程序只要使用SpringDAO模板,例如JdbcTemplate进行数据访问,一定没有数据库连接泄露问题!如果程序中显式的获取了数据连接Connection,则需要手工关闭它,否则就会泄露!
 - 当Spring事务方法运行时,就产生一个事务上下文,它在本事务执行线程中对同一个数据源绑定了一个唯一的数据连接,所有被该事务上下文传播的方法都共享这个连接。要获取这个连接,如要使用Spirng的资源获取工具类DataSourceUtils。
 - 事务管理上下文就好比一个盒子,所有的事务都放在里面。如果在某个事务方法中开启一个新线程,新线程中执行另一个事务方法,则由上面第二条可知这两个方法运行于两个独立的事务中,但是:如果使用DataSourcesUtils,则新线程中的方法可以从事务上下文中获取原线程中的数据连接!
 
Spring单实例、多线程安全、事务解析的更多相关文章
- Servlet单实例多线程模式
		
http://kakajw.iteye.com/blog/920839 前言:Servlet/JSP技术和ASP.PHP等相比,由于其多线程运行而具有很高的执行效率.由于Servlet/JSP默认是以 ...
 - Servlet 生命周期、工作原理-是单实例多线程
		
Servelet是单实例多线程的 参考:servlet单实例多线程模式 一.Servlet生命周期 大致分为4部:Servlet类加载-->实例化-->服务-->销毁 1.Web C ...
 - 实现单实例多线程安全API问题
		
前阵子写静态lib导出单实例多线程安全API时,出现了CRITICAL_SECTION初始化太晚的问题,之后查看了错误的资料,引导向了错误的理解,以至于今天凌晨看到另一份代码,也不多想的以为singl ...
 - Java ,单实例 多线程 ,web容器,servlet与struts1-2.x系列,线程安全的解决
		
1.Servlet是如何处理多个请求同时访问呢? 回答:servlet是默认采用单实例,多线程的方式进行.只要webapp被发布到web容器中的时候,servlet只会在发布的时候实例化一次,serv ...
 - Singleton、MultiThread、Lib——实现单实例无锁多线程安全API
		
前阵子写静态lib导出单实例多线程安全API时,出现了CRITICAL_SECTION初始化太晚的问题,之后查看了错误的资料,引导向了错误的理解,以至于今天凌晨看到另一份代码,也不多想的以为s ...
 - Servlet 单例多线程
		
Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...
 - servlet单例多线程
		
Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...
 - Servlet 单例多线程【转】
		
源地址:Servlet 单例多线程 Servlet如何处理多个请求访问?Servlet容器默认是采用单实例多线程的方式处理多个请求的:1.当web服务器启动的时候(或客户端发送请求到服务器时),Ser ...
 - [转]Servlet 单例多线程
		
Servlet如何处理多个请求访问? Servlet容器默认是采用单实例多线程的方式处理多个请求的: 1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在 ...
 
随机推荐
- HDU-Minimum Inversion Number(最小逆序数)
			
Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of ...
 - iOS 开发小结
			
一,经历 1> 在编写以前有过的类似的新功能时,如果以前的开发人员没有写明明确的注释和开发需求,一定要仔细阅读所有代码,每一句代码都有它存在的意义. 2> 例如,只以为是[self.ful ...
 - weblogic部署项目包,报空指针错误
			
贴出 报错代码 <weblogic> <> <> <1479765377228> <BEA-240003> <Console enco ...
 - POJ 1564   经典dfs
			
1.POJ 1564 Sum It Up 2.总结: 题意:在n个数里输出所有相加为t的情况. #include<iostream> #include<cstring> #in ...
 - windows一些快捷键
			
1.Win + __ 1)Win + L 锁屏 2)Win + E 资源管理器(就是打开硬盘) 3)Win + D 回到桌面 4)Win + Tab 3D方式切换程序窗口 5)Win + R 运行命令 ...
 - MongoDB介绍及安装
			
一.介绍: 1.NoSql(非关系型的数据库)成了一个极其热门的新领域,非关系数据库产品的发展非常迅速.MongoDB是NoSql的其中一种较为热门的非关系型数据库.查阅很多资料.其他博客和网站,借着 ...
 - Crossing River
			
Crossing River 题目链接:http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=26251 题意: N个人希望去过 ...
 - 黑马程序员----java基础笔记上(毕向东)
			
------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 笔记一共记录了毕向东的java基础的25天课程,分上.中.下 本片为上篇,涵盖前10天课程 1. ...
 - Maching Learning 学习资料
			
A星(A*, A Star)算法详解 CSDN技术主题月----“深度学习”代码笔记专栏 UC Berkeley CS188 Intro to AI
 - winfrom 无边框窗体移动和阴影
			
无边框窗体移动: //窗体移动API [DllImport("user32.dll")] public static extern bool ReleaseCapture(); [ ...