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就被加载并实例化(只存在 ...
随机推荐
- ACM 取石子(七)
取石子(七) 时间限制:1000 ms | 内存限制:65535 KB 难度:1 描述 Yougth和Hrdv玩一个游戏,拿出n个石子摆成一圈,Yougth和Hrdv分别从其中取石子,谁先取完 ...
- ACM 分数加减法
分数加减法 时间限制:3000 ms | 内存限制:65535 KB 难度:2 描述 编写一个C程序,实现两个分数的加减法 输入 输入包含多行数据 每行数据是一个字符串,格式是" ...
- [题解+总结]NOIP2015模拟题2
// 此博文为迁移而来,写于2015年7月22日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102w72i.html 1.总 ...
- iOS 开发技巧总结
1.添加定时器的常用代码 - (void)delayEnableTabButton { self.tabChannelButton.enabled = NO; [self appendTimer]; ...
- java list 交集 并集 差集 去重复并集
package com; import java.util.ArrayList;import java.util.Iterator;import java.util.List; public clas ...
- android中的ActionBar和ToolBar
一.ToolBar 1.概述 Google在2015的IO大会上发布了系列的Material Design风格的控件.其中ToolBar是替代ActionBar的控件.由于ActionBar在各个安卓 ...
- Java Web include指令和动作的区别
- github page 构建自己的页面
新建一个仓库.命名为:<你的账号>.github.io 然后上传一个index.html即可 打开浏览器输入:<你的账号>.github.io 即可访问
- 本内容中发现无效字符。处理资源 'file:///C:/Users/XDJ/Desktop/1111/press.xml' 时出错。第 5 行,位置: 11 <author>ƽ
粘贴到编译器中, 然后在复制出即可.
- 安卓模拟器研究-root
http://www.bluestacks.cn/index.asp 下载最新的 BlueStacks 尝试了很久都没有root成功. 百度搜索 找到经验文档 http://jingyan.baid ...