java简单实现事务控制的demo

简介: java简单实现事务控制的demo

1.实现事务控制的基本思路



1.1代理机制


最原始的做法就是在每个数据库操作的时候通过用一个链接传递实现对事务的控制。
这样的话重复代码太多,不容易控制事务。
如果用代理机制的话就可以很方便的解决这个问题。
代理的是什么?
事务统一的开启,提交,回滚,释放
复制代码


1.2事务的获取要保证当前的线程处理是唯一的


这里用到了Java的ThreadLocal会保证当前的线程只有一个链接再用
复制代码


2.实现过程



2.1数据库链接工具类


public class JDBCUtil {
  private JDBCUtil() {
  }
  private static ThreadLocal<Connection> threadConn = new ThreadLocal<Connection>();
  // 获取数据库连接
  public static Connection getConnection() {
    Connection conn = threadConn.get();
    if (conn == null) {
      try {
        System.out.println("创建链接");
        Class.forName("oracle.jdbc.driver.OracleDriver");//找到oracle驱动器所在的类
        String url="jdbc:oracle:thin:@127.0.0.1:1521:orcl"; //URL地址
        String username="test";
        String password="test";
        conn=DriverManager.getConnection(url, username, password);
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (SQLException e) {
        e.printStackTrace();
      }
      threadConn.set(conn);
    }
    return conn;
  }
  // 设置事务手动提交
  public static void benigTransction(Connection conn) {
    System.out.println("事务手动提交");
    try {
      if (conn != null) {
        if (conn.getAutoCommit()) {
          conn.setAutoCommit(false);
        }
      }
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  // 提交事务
  public static void endTransction(Connection conn) {
    System.out.println("提交事务");
    try {
      if (conn != null) {
        if (!conn.getAutoCommit()) {
          conn.commit();
        }
      }
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  // 设置Connection的原始状态
  public static void recoverTransction(Connection conn) {
    System.out.println("恢复设置");
    try {
      if (conn != null) {
        if (conn.getAutoCommit()) {
          conn.setAutoCommit(false);
        } else {
          conn.setAutoCommit(true);
        }
      }
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  // 发生异常回滚事务
  public static void rollback(Connection conn) {
    System.out.println("回滚设置");
    try {
      if (conn != null) {
        conn.rollback();
      }
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  // 关闭连接,并将其从当前线程删除
  public static void close() {
    System.out.println("关闭删除");
    Connection conn = threadConn.get();
    if (conn != null) {
      try {
        conn.close();
        conn = null;
        threadConn.remove();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
  }
}
复制代码


2.2数据库事务控制的动态代理类


public class DaoProxy implements MethodInterceptor {
  public Object intercept(Object object, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
    // 用于接收参数
    // 如果是以下方法开头,则代理事务
    Object result=null;
    if (method.getName().startsWith("add") ||
      method.getName().startsWith("del")||
      method.getName().startsWith("update")) {
      Connection conn = JDBCUtil.getConnection();
      try {
        // 手动提交事务
        JDBCUtil.benigTransction(conn);
        result=proxy.invokeSuper(object, objects);
        // 提交事务
        JDBCUtil.endTransction(conn);
      } catch (Exception e) {
        e.printStackTrace();
        // 回滚事务
        JDBCUtil.rollback(conn);
      } finally {
        // 还原状态
        JDBCUtil.recoverTransction(conn);
        JDBCUtil.close();
      }
    }else {
      result=proxy.invokeSuper(object, objects);
    }
    return result;
  }
}
复制代码


2.3对sql提交的基类


public class BaseDao {
  public int insert(String sql,List<Object> values) throws SQLException {
    Connection con=JDBCUtil.getConnection();
    PreparedStatement pre=con.prepareStatement(sql);
    for(int index=0;index<values.size();index++) {
       Object obj=values.get(index);
       if(obj.getClass().isInstance(Integer.class)) {
         pre.setInt(index+1, (Integer)obj);
       }else if(obj.getClass().isInstance(Double.class)) {
         pre.setDouble(index+1, (Double)obj);
       }else if(obj.getClass().isInstance(BigDecimal.class)) {
         pre.setBigDecimal(index+1, (BigDecimal)obj);
       }else if(obj.getClass().isInstance(java.sql.Date.class)) {
         pre.setDate(index+1, (java.sql.Date)obj);
       }else if(obj.getClass().isInstance(java.util.Date.class)) {
         pre.setDate(index+1, new java.sql.Date(((java.util.Date)obj).getTime()));
       }else {
         pre.setString(index+1, obj.toString());
       }
    }
    return pre.executeUpdate();
  }
}
复制代码


2.4数据添加的测试DAO


public class DAOTest extends BaseDao{
  public void addTest(String test) throws SQLException {
    String id=UUID.randomUUID().toString().replace("-", "");
    String addSql="insert into TEST (ID,TEST) values (?,?)";
    List<Object> values=new ArrayList<Object>();
    values.add(id);
    values.add(test);
        this.insert(addSql, values);
  }
  public void addTestError(String test) throws SQLException {
    String id=UUID.randomUUID().toString().replace("-", "");
    String addSql="insert into TEST (ID,TEST) values (?,?)";
    List<Object> values=new ArrayList<Object>();
    values.add(id);
    values.add(test);
        this.insert(addSql, values);
        throw new SQLException("回滚测试");
  }
}
复制代码


2.4效果


public class TestDao {
  public static void main(String[] args) throws SQLException {
    DaoProxy daoProxy = new DaoProxy();
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(DAOTest.class);
    enhancer.setCallback(daoProxy);
    DAOTest dt=(DAOTest)enhancer.create();
    dt.addTest("123");
    dt.addTestError("456");
  }
}
复制代码


网络异常,图片无法展示
|


网络异常,图片无法展示
|

相关文章
|
6天前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
6天前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
2月前
|
数据采集 Java
selenium+java入门demo
selenium+java入门demo
32 4
|
6天前
|
前端开发 Java 数据库连接
一天十道Java面试题----第五天(spring的事务传播机制------>mybatis的优缺点)
这篇文章总结了Java面试中的十个问题,包括Spring事务传播机制、Spring事务失效条件、Bean自动装配方式、Spring、Spring MVC和Spring Boot的区别、Spring MVC的工作流程和主要组件、Spring Boot的自动配置原理和Starter概念、嵌入式服务器的使用原因,以及MyBatis的优缺点。
|
5天前
|
Java
MQTT(EMQX) - Java 调用 MQTT Demo 代码
MQTT(EMQX) - Java 调用 MQTT Demo 代码
8 0
MQTT(EMQX) - Java 调用 MQTT Demo 代码
|
6天前
|
算法 关系型数据库 MySQL
一天五道Java面试题----第七天(mysql索引结构,各自的优劣--------->事务的基本特性和隔离级别)
这篇文章是关于MySQL的面试题总结,包括索引结构的优劣、索引设计原则、MySQL锁的类型、执行计划的解读以及事务的基本特性和隔离级别。
|
5天前
|
算法 关系型数据库 MySQL
一天五道Java面试题----第七天(mysql索引结构,各自的优劣--------->事务的基本特性和隔离级别)
这篇文章是关于MySQL的面试题总结,包括索引结构的优劣、索引设计原则、MySQL锁的类型、执行计划的解读以及事务的基本特性和隔离级别。
|
2月前
|
Java 测试技术 数据库连接
解密Java事务传播行为与隔离级别:案例详解与解决方案
解密Java事务传播行为与隔离级别:案例详解与解决方案
19 1
|
2月前
|
Java Spring
Java事务的传播
Java事务的传播
10 0
|
2月前
|
Java
【Java基础】 学生管理系统的简单实现
学生管理系统的简单实现
74 3