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就被加载并实例化(只存在 ...
随机推荐
- 51Nod 1001 数组中和等于K的数对 Label:Water
给出一个整数K和一个无序数组A,A的元素为N个互不相同的整数,找出数组A中所有和等于K的数对.例如K = 8,数组A:{-1,6,5,3,4,2,9,0,8},所有和等于8的数对包括(-1,9),(0 ...
- 百度mobile UI组件GMU demo学习1-结构和初始化
移动web现在已经是zepto的天下,但是一直找不到合适UI库,找了一段时间,终于找到了百度的ui库gum和inter 的 appframework UI库 相比之下,百度的UI库更接地气,配合百度强 ...
- CF 55D. Beautiful numbers(数位DP)
题目链接 这题,没想出来,根本没想到用最小公倍数来更新,一直想状态压缩,不过余数什么的根本存不下,看的von学长的blog,比着写了写,就是模版改改,不过状态转移构造不出,怎么着,都做不出来. #in ...
- 实用的Bootstrap的扩展和插件集合
bootstrap插件 http://www.missyuan.net/school/other_2014/other_16472.html http://www.oschina.net/news/5 ...
- [转] 擎天哥as3教程系列第二回——性能优化
所谓性能优化主要是让游戏loading和运行的时候不卡. 一 优化fla导出的swf的体积? 1, 在flash中,舞台上的元件最多,生成的swf越大,库里面有连接名的元件越多,swf越大.当舞台 ...
- 用clip剪裁实现半圆
定义和用法 clip 属性剪裁绝对定位元素. 说明 这个属性用于定义一个剪裁矩形.对于一个绝对定义元素,在这个矩形内的内容才可见.出了这个剪裁区域的内容会根据 overflow 的值来处理.剪裁区域可 ...
- CSS3两个动画顺序衔接播放
问题描述: 第一个动画先播放,播放完成后,第二个动画紧接着播放. 解决办法: 1. 将第二个的延迟时间(animation-delay) 设置成第一个的持续时间( animation-duration ...
- HTTPS原理介绍
内容来源于:http://www.guokr.com/post/114121/ 自己做个备忘. 二.HTTPS到底安全吗? 这个答案是肯定的,很安全.谷歌公司已经行动起来要大力推广HTTPS的使用,在 ...
- mztree使用示例
mztree使用:http://www.myexception.cn/open-source/1014169.html jquery的treeview使用:http://www.cnblogs.com ...
- 数据结构 C++ 单链表 一元多项式的相加
#include <iostream> using namespace std; struct Node { double coe; //系数 int exp; //指数 Node *ne ...