自定义事务管理器TransactionManager对象

(5) 2024-07-14 15:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
自定义事务管理器TransactionManager对象,希望能够帮助你!!!。

自定义事务管理器TransactionManager对象

以aop思想,实现事务管理切面

1. DataSource注册容器

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--开启包扫描注解--> <context:component-scan base-package="com.hang"/> <!--导入jdbc.properties文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--配置druid数据库连接池--> <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource"> <property name="url" value="${jdbc.url}"/> <property name="driverClassName" value="${jdbc.driver}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="initialSize" value="${jdbc.initialSize}"/> </bean> <!--开启aop注解--> <aop:aspectj-autoproxy/> </beans> 

2. 定义事务管理器MyTransactionManager对象

定义事务管理器MyTransactionManager对象,注册进spring容器。(依赖Druid连接池,获取连接,开始事务,提交事务,回滚事务,关闭连接)

@Component public class MyTransactionManager { 
    @Autowired private DataSource dataSource; // 获取连接 public Connection getConnection(){ 
    Connection conn = null; try { 
    conn = dataSource.getConnection(); ConnUtil.setConn(conn); } catch (SQLException e) { 
    e.printStackTrace(); } return conn; } // 开始事务 public void openTransaction(){ 
    try { 
    ConnUtil.getConn().setAutoCommit(false); } catch (SQLException e) { 
    e.printStackTrace(); } } // 提交事务 public void openCommit(){ 
    try { 
    ConnUtil.getConn().commit(); } catch (SQLException e) { 
    e.printStackTrace(); } } // 回滚事务 public void openRollback(){ 
    try { 
    ConnUtil.getConn().rollback(); } catch (SQLException e) { 
    e.printStackTrace(); } } // 关闭连接 public void closeConnection(){ 
    Connection conn = ConnUtil.getConn(); try { 
    if (conn!=null){ 
    conn.close(); } } catch (SQLException e) { 
    e.printStackTrace(); } } public DataSource getDataSource() { 
    return dataSource; } public void setDataSource(DataSource dataSource) { 
    this.dataSource = dataSource; } } 

3. 定义dao接口

定义dao接口,使用jdbc定义dao实现,不要使用mybatis,把dao实现注册spring容器(curd)

public interface SysUserDao { 
    SysUser queryById(Integer id) throws Exception; Integer insert(SysUser sysUser) throws Exception; int update(SysUser sysUser); int deleteById(Long id); } 
@Repository public class SysUserDaoImpl implements SysUserDao { 
    private Connection conn = null; private ResultSet rs = null; private PreparedStatement ps = null; @Override public SysUser queryById(Integer id) throws Exception { 
    SysUser sysUser = null; conn = ConnUtil.getConn(); ps = conn.prepareStatement("select * from db_stage_three.sys_user where id = ?"); ps.setInt(1, id); rs = ps.executeQuery(); if (rs.next()) { 
    sysUser = new SysUser(); sysUser.setUname("hello"); } return sysUser; } @Override public Integer insert(SysUser sysUser) throws Exception { 
    Integer result = null; conn = ConnUtil.getConn(); ps = conn.prepareStatement("insert into db_stage_three.sys_user ( uname, uphone, upwd, uwechat, uemail, role_id, dept_id) values (?,?,?,?,?,?,?)"); ps.setString(1, sysUser.getUname()); ps.setString(2, sysUser.getUphone()); ps.setString(3, sysUser.getUpwd()); ps.setString(4, sysUser.getUwechat()); ps.setString(5, sysUser.getUemail()); ps.setInt(6, sysUser.getRoleId()); ps.setInt(7, sysUser.getDeptId()); result = ps.executeUpdate(); return result; } @Override public int update(SysUser sysUser) { 
    return 0; } @Override public int deleteById(Long id) { 
    return 0; } } 

4. 定义service接口

定义service接口,定义service实现,注册容器(curd)。

public interface SysUserService { 
    SysUser queryById(Integer id); SysUser insert(SysUser sysUser); } 
@Service() public class SysUserServiceImpl implements SysUserService { 
    @Resource private SysUserDao sysUserDao; @Override public SysUser queryById(Integer id) { 
    Connection conn = null; // 织入获取连接,开始事务,提交事务,回滚事务,关闭连接 SysUser sysUser = null; try { 
    sysUser = this.sysUserDao.queryById(id); } catch (Exception e) { 
    e.printStackTrace(); } return sysUser; } @Transaction // 使用基于自定义注解方式定义切入点表达式 @Override public SysUser insert(SysUser sysUser) { 
    try { 
    this.sysUserDao.insert(sysUser); } catch (Exception e) { 
    e.printStackTrace(); } int i = 1/0; return sysUser; } } 

自定义注解代码如下:

@Target({ 
   ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Transaction { 
    } 

5. 定义事务切面(依赖MyTransactionManag)

定义事务切面(依赖MyTransactionManag),定义环绕通知,织入到service层的数据库操作方法,执行方法之前打开事务,异常回滚,方法返回提交事务,最终关闭连接。定义 ServiceTransAspect 类作为切面

@Component @Aspect public class ServiceTransAspect { 
    @Autowired private MyTransactionManager transactionManager; // 基于 AspectJ 的切入点表达式 @Pointcut("execution(* com.hang.service.impl.SysUserServiceImpl.*(..))") public void servicePointCut() { 
    } // 后置通知关闭数据库连接对象 @After("servicePointCut()") public void closeConnection(){ 
    Connection conn = ConnUtil.getConn(); if (conn!=null){ 
    try { 
    conn.close(); ConnUtil.clear(); conn = null; } catch (SQLException e) { 
    e.printStackTrace(); } } } // 基于自定义注解形式 @Pointcut("@annotation(com.hang.aspect.Transaction)") public void annotationPointCut() { 
    } // 环绕通知 实现事务的开启、回滚、提交和连接对象的关闭 @Around(value = "annotationPointCut()") public Object serviceManage(ProceedingJoinPoint pjp) { 
    Object result = null; try { 
    transactionManager.getConnection(); transactionManager.openTransaction(); result = pjp.proceed(); transactionManager.openCommit(); } catch (Throwable throwable) { 
    transactionManager.openRollback(); throwable.printStackTrace(); } finally { 
    transactionManager.closeConnection(); } return result; } } 

6. 自定义工具类

在并发环境下,如果没使用ThreadLocal类维护线程内部的局部变量Connection(单Connection对象),两个线程共同访问一个公共变量。例如A用户获取数据库连接对象,并将Connection对象占为己有,对数据进行操作时,B用户也获取到数据库连接对象,获取Connection对象,此时A不具有Connection对象,B用户完成事务提交关闭连接,此时Connection对象为null,A用户数据则会提交失败。

ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get和set方法访问)时能保证各个线程的变量相对独立于其他线程内的变量。

对ThreadLocal作用的总结:

  1. 线程并发: 在多线程并发的场景下
  2. 传递数据: 我们可以通过ThreadLocal在同一线程,不同组件中传递公共变量
  3. 线程隔离: 每个线程的变量都是独立的,不会互相影响
@Component public class ConnUtil { 
    private static ThreadLocal<Connection> threadLocalConn = new ThreadLocal<>(); @Resource private MyTransactionManager tm; private static MyTransactionManager manager; public static void clear() { 
    threadLocalConn.remove(); } @PostConstruct public void setTransactionManager(){ 
    manager = tm; } public static Connection getConn() { 
    Connection connection = threadLocalConn.get(); if (connection!=null){ 
    return connection; }else { 
    return manager.getConnection(); } } public static void setConn(Connection conn) { 
    threadLocalConn.set(conn); } } 

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复