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");
  }
}
复制代码


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


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

相关文章
|
4月前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
4月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
6月前
|
数据采集 Java
selenium+java入门demo
selenium+java入门demo
53 4
|
2月前
|
消息中间件 分布式计算 Java
大数据-73 Kafka 高级特性 稳定性-事务 相关配置 事务操作Java 幂等性 仅一次发送
大数据-73 Kafka 高级特性 稳定性-事务 相关配置 事务操作Java 幂等性 仅一次发送
39 2
|
4月前
|
小程序 Java 开发工具
【Java】@Transactional事务套着ReentrantLock锁,锁竟然失效超卖了
本文通过一个生动的例子,探讨了Java中加锁仍可能出现超卖问题的原因及解决方案。作者“JavaDog程序狗”通过模拟空调租赁场景,详细解析了超卖现象及其背后的多线程并发问题。文章介绍了四种解决超卖的方法:乐观锁、悲观锁、分布式锁以及代码级锁,并重点讨论了ReentrantLock的使用。此外,还分析了事务套锁失效的原因及解决办法,强调了事务边界的重要性。
134 2
【Java】@Transactional事务套着ReentrantLock锁,锁竟然失效超卖了
|
4月前
|
前端开发 Java 数据库连接
一天十道Java面试题----第五天(spring的事务传播机制------>mybatis的优缺点)
这篇文章总结了Java面试中的十个问题,包括Spring事务传播机制、Spring事务失效条件、Bean自动装配方式、Spring、Spring MVC和Spring Boot的区别、Spring MVC的工作流程和主要组件、Spring Boot的自动配置原理和Starter概念、嵌入式服务器的使用原因,以及MyBatis的优缺点。
|
4月前
|
算法 关系型数据库 MySQL
一天五道Java面试题----第七天(mysql索引结构,各自的优劣--------->事务的基本特性和隔离级别)
这篇文章是关于MySQL的面试题总结,包括索引结构的优劣、索引设计原则、MySQL锁的类型、执行计划的解读以及事务的基本特性和隔离级别。
|
4月前
|
Java
MQTT(EMQX) - Java 调用 MQTT Demo 代码
MQTT(EMQX) - Java 调用 MQTT Demo 代码
197 0
MQTT(EMQX) - Java 调用 MQTT Demo 代码
|
6月前
|
Java 测试技术 数据库连接
解密Java事务传播行为与隔离级别:案例详解与解决方案
解密Java事务传播行为与隔离级别:案例详解与解决方案
70 1
|
6月前
|
Java
【Java基础】 学生管理系统的简单实现
学生管理系统的简单实现
94 3