事务处理
1.事务管理在Dao层
2. 事务管理在业务层
实现:
涉及到的组件:
- OpenSessionInViewFilter
- TransactionManager
- ThreadLocal
- ConnUtil
- BaseDAO
(1)拦截器(OpenSessionInViewFilter)
package com.fruits.filters; import com.fruits.trans.TransactionManager; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; import java.sql.SQLException; @WebFilter("*.do") public class OpenSessionInViewFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { TransactionManager transactionManager = new TransactionManager(); try { transactionManager.beginTrans(); // 开始事务 filterChain.doFilter(servletRequest,servletResponse); // 放行 transactionManager.commit(); //提交事务 } catch (SQLException e) { e.printStackTrace(); try { transactionManager.rollback(); //回滚事务 } catch (SQLException ex) { ex.printStackTrace(); } } } @Override public void destroy() { } }
(2)封装事务操作
public class TransactionManager { //该类用来封装事务的操作:开启事务、提交事务、关闭事务。。。 //开启事务 public void beginTrans() throws SQLException { ConnUtil.getConn().setAutoCommit(false); //获取连接,不自动提交 } //提交事务 public void commit() throws SQLException { ConnUtil.getConn().commit(); ConnUtil.closeConn(); } //回滚事务 public void rollback() throws SQLException { ConnUtil.getConn().rollback(); ConnUtil.closeConn(); } }
(3)获取数据库连接
package com.fruits.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ConnUtil { public static final String driver = "com.mysql.cj.jdbc.Driver"; public static final String url =" jdbc:mysql://localhost:3306/mytest?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8"; public static final String username =" root"; public static final String password = "123456"; private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>(); private static Connection createConn(){ try { //加载驱动 Class.forName(driver); //通过驱动管理器获取连接对象 return DriverManager.getConnection(url,username,password); } catch (Exception e) { e.printStackTrace(); } return null; } public static Connection getConn(){ Connection conn = threadLocal.get(); //获取到Connection对象 if(conn == null){ conn = createConn(); //如果threadLocal为空,重新获取Connection对象 threadLocal.set(conn); //获取到Connection对象值就设置到threadLocal中 } return threadLocal.get(); //重新获取到Connection对象 } public static void closeConn() throws SQLException { Connection conn = threadLocal.get(); //获取到Connection对象 if(conn == null){ return; } if(!conn.isClosed()){ conn.close(); threadLocal.set(null); } } }
3. ThreadLocal
ThreadLocal 本地线程:同一个线程中进行数据通信。通过set方法在当前线程上存储数据、通过get方法在当前线程上获取数据
- set方法源码分析:
public void set(T value) { Thread t = Thread.currentThread(); //获取当前的线程 ThreadLocalMap map = getMap(t); //每一个线程都维护各自的一个容器(ThreadLocalMap) if (map != null) map.set(this, value); //这里的key对应的是ThreadLocal,因为我们的组件中需要传输(共享)的对象可能会有多个(不止Connection) else createMap(t, value); //默认情况下map是没有初始化的,那么第一次往其中添加数据时,会去初始化 }
-get方法源码分析:
public T get() { Thread t = Thread.currentThread(); //获取当前的线程 ThreadLocalMap map = getMap(t); //获取和这个线程(企业)相关的ThreadLocalMap(也就是工作纽带的集合) if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); //this指的是ThreadLocal对象,通过它才能知道是哪一个工作纽带 if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; //entry.value就可以获取到工具箱了 return result; } } return setInitialValue(); }