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就被加载并实例化(只存在 ...
随机推荐
- codeforces round #234B(DIV2) A Inna and Choose Options
#include <iostream> #include <string> #include <vector> using namespace std; ; ,,, ...
- 【bzoj2809】[Apio2012]dispatching 左偏树
2016-05-31 15:56:57 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2809 直观的思想是当领导力确定时,尽量选择薪水少的- ...
- HDU 1251 Trie树模板题
1.HDU 1251 统计难题 Trie树模板题,或者map 2.总结:用C++过了,G++就爆内存.. 题意:查找给定前缀的单词数量. #include<iostream> #incl ...
- JS引用另外JS文件的顺序问题。
1.在a.js中可以引用b.js文件,这样就可以在网页中只引用a.js文件,从而可以使用a.js和b.js文件中的所有方法. 引用格式如下:document.write('<script typ ...
- Windows 下安装使用docker swarm machine docker toolbox
下载docker 集成安装环境 http://get.daocloud.io/#install-toolbox 这个网站很不错,下载 这个集成了 docker docker-machine ,还有gi ...
- 使用C语言在windows下一口气打开一批网页
作者:郝峰波 mail : fengbohello@qq.com 本博客地址:http://www.cnblogs.com/fengbohello/p/4374450.html 1.核心函数说明 核心 ...
- 30分钟学会使用grunt打包前端代码
http://www.cnblogs.com/yexiaochai/p/3603389.html
- 四种读写方案IO流 (JAVA)
File类用于访问文件或目录的属性 流:指一连串流动的字符,是以先进先出的方式发送信息的通道.程序和数据源之间是通过流联系起来的. 第一套:字节流读取写入方案 FileInputStream :字节流 ...
- 【HDU4630 No Pain No Game】 dp思想+线段树的离线操作
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4630 题意:给你n个数据范围在[1,n]中的数,m个操作,每个操作一个询问[L,R],让你求区间[L, ...
- thinkphp自定义权限管理之名称判断
权限管理,就是给不同的用户分配不同的权限.当用户登录或者操作时候进行判断,来阻止用户进行权限以外的操作.本次讲的是当用户登录一刻,只显示权限开启的内容. 一.建立数据库. 1.权限表funcla.来存 ...