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就被加载并实例化(只存在 ...
随机推荐
- [Java] java.util.Arrays 中使用的 sort 采用的算法 (转)
http://book.douban.com/annotation/15154366/Q: java.util.Arrays 中使用的 sort 采用的是什么算法? A: java中Arrays. ...
- HDU 2824 简单欧拉函数
1.HDU 2824 The Euler function 2.链接:http://acm.hdu.edu.cn/showproblem.php?pid=2824 3.总结:欧拉函数 题意:求(a ...
- 在不知道json格式的情况下如何使用cjson进行解析
假设我们有一个json字符串,但是我们不知道这个json的组织方式,那么如何进行解析呢,下面就给一个小例子. 1.我们的json串如下: { "aStr": "aaaaa ...
- 索引器、哈希表Hashtabl、字典Dictionary(转)
一.索引器 索引器类似于属性,不同之处在于它们的get访问器采用参数.要声明类或结构上的索引器,使用this关键字. 示例: 索引器示例代码 /// <summary> /// 存储星 ...
- Bootstrap 4上线啦!!!
Bootstrap 官方于 2015 年 8 月 19 日发布了其最新版本 Bootstrap v4.0.0-alpha. Bootstrap 4 的开发是一项浩大的工程,将近一年的开发,几乎是对整个 ...
- Stereo Matching 立体匹配学习资料
Middlebury Stereo Evaluation Camera Calibration and 3D Reconstruction OpenCV学习笔记(18)双目测距与三维重建的OpenCV ...
- [LintCode] Add and Search Word 添加和查找单词
Design a data structure that supports the following two operations: addWord(word) and search(word) s ...
- 用JAVA写一个日历计划
效果图(自己需要在前台加css修饰)
- c#中enum的用法小结
转自:http://blog.csdn.net/moxiaomomo/article/details/8056356 enums枚举是值类型,数据直接存储在栈中,而不是使用引用和真实数据的隔离方式来存 ...
- IIS 注册4.0 Framework
打开cmd ,运行如下命令 C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -i