Spring事务
Posted tjqblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring事务相关的知识,希望对你有一定的参考价值。
ThreadLocal在bean的管理中的使用
当运行于多线程环境下的某个对象使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程独立分配一个变量副本,每个线程都使用自己的变量副本,从而不影响其他其他线程。
public class SequenNumber { private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() { public Integer initialValue() { return 0; } }; public int getNextNum() { seqNum.set(seqNum.get()+1); return seqNum.get(); } public static void main(String[] args) { SequenNumber sn = new SequenNumber(); TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); } private static class TestClient extends Thread { private SequenNumber sn; public TestClient(SequenNumber sn) { super(); this.sn = sn; } @Override public void run() { System.out.println(sn.hashCode()); for(int i=0;i<3;i++) { System.out.println(Thread.currentThread().getName()+"---"+sn.getNextNum()); } } } }
1304030204 1304030204 1304030204 Thread-0---1 Thread-1---1 Thread-0---2 Thread-2---1 Thread-0---3 Thread-1---2 Thread-1---3 Thread-2---2 Thread-2---3
结果里面可以看出,每个线程都共享一个SequenNumber对象,但是实际上他们没有相互干扰,各自产生自己的序列号,因为ThreadLocal为每个线程提供一个单独的副本。
一般来说,只有无状态bean才能在多线程环境下被设计为单例的,但是spring里面的bean绝大部分是单例的, 然而这些bean并不是无状态的,spring使用ThreadLocal对这些无状态的bean进行封装,让他们能以单例在多线程环境下运行。例如 web应用中 划分为三层 Controller Service Dao,一般来说从接受请求到返回响应的所有经过过程调用均是同一线程,这样用户就可以根据需要,将一些非线程安全的变量以ThreadLocal存放,在同一请求响应过程中,所有对象访问的是同一ThreadLocal变量所绑定的。下面演示这一思路。
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; public class TestDao { private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<>(); public static Connection getConnection() { Connection conn = connThreadLocal.get(); if(conn==null) { try { conn = DriverManager.getConnection("自己的数据库配置"); } catch (SQLException e) { e.printStackTrace(); } connThreadLocal.set(conn); } return conn; } public void addData() throws Exception{ Statement statement =getConnection().createStatement(); //执行数据库操作 } }
不同的请求对应的线程在使用TestDao时先通过ThreadLocal对象判断当前线程是否持有Connection对象,如果没有那么创建一个 并且将其设置到ThreadLocal中,如果不为null,说明当前线程已经拥有Connection对象 可以直接使用,这样就可以保证不同的线程使用自己独立的Connection对象,而不会使用其他线程的Connection对象,此时 TestDao就可以被设置为单例的了。当然 这个例子是比较粗糙的 只能实现TestDao的多个方法共享一个Connection对象,无法实现其他dao也共同使用一个Connection对象,,要做到这一点需要在一个外部的共同类使用ThreadLocal保存Connection对象,这个例子只是说明一下spring改造bean的思路。
spring 通过TransactionSynchronizationManager将Dao Service中影响线程安全的所有状态(资源,事务名,事务状态,隔离级别,事务激活状态等等)统一抽取到这个类中,因此Dao和Service可以摘掉非线程安全的帽子 使用单例来运行。
事务的传播行为,事务传播是spring事务管理的重要概念 重要不言而喻。
spring中默认的事务传播行为时PROPAGATION_REQUIRED,当多个事务方法嵌套调用时,那么这些事务方法就工作在同一事务环境下,后面的事务方法会加入到前面的事务环境下,也就是说 能统一回滚。
以上是关于Spring事务的主要内容,如果未能解决你的问题,请参考以下文章
使用 OnItemClickListener 列出视图片段到片段事务