数据库事务及代码实现

数据库事务及代码实现

package com.shan.transaction;

import com.mysql.fabric.ShardTable;
import com.shan.util.JDBCUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLOutput;

/**
 * 1.什么叫数据库事物
 *  事物:一组逻辑操作单元,使数据从一种状态转换到另一种状态。
 *      -->一组逻辑操作单元:一个或多个DML操作
 * 2.事物处理
 *  事务处理是将多个操作或者命令一起执行,所有命令全部成功执行才意味着该事务的成功,任何一个命令失败都意味着该事务的失败。
 * 3.以银行转账为例(100块都不给),
 *      A要给B 转账100元,
 *      A转账的指令已经成功发出,而B 由于未知的原因接收失败,
 *      如果两个命令单独执行,那么A账户少了100块,但是B又没收到100块,显而易见是不合理的;
 *      如果将A向B 转账100元当成一个事务处理,那么由于B 接收的失败,整个转账事务都将失败,A不会少100,B更不会增加100,这个时候“100块都不给”才是合理的情况。
 * 4.数据一旦提交,就不可回滚
 *      a. DDL操作一旦执行,都会自动提交
 *      b. AML默认情况下,一旦执行,就会自动提交
 *          -->可以设置set automint = false 取消DML操作的自动提交
 *      c. 默认在关闭连接时,会自动提交数据
 * @author shan
 * @date 2021/5/17
 */
public class transactionTest {
    /**
     * 针对与数据表user——table来说
     * AA用户给BB用户转载100
     *
     * update user_table set balance = balance - 100 where user = 'AA'
     * update user_table set balance = balance + 100 where user = 'BB'
     *
     */
    public static void main(String[] args) {

        模拟转账异常
//
//        String sql1 = "update user_table set balance = balance - 100 where user = ?";
//        update(sql1, "AA");
//
//        //模拟网络异常
//        System.out.println(10/0);
//
//        String sql2 = "update user_table set balance = balance + 100 where user = ?";
//        update(sql2, "BB");
//
//        System.out.println("转账成功");


        Connection conn = null;
        try {
            conn = JDBCUtils.getConnection();
            System.out.println("默认:" + conn.getAutoCommit());
            //取消数据的自动提交功能
            conn.setAutoCommit(false);

            String sql1 = "update user_table set balance = balance - 100 where user = ?";
            update1(conn, sql1, "AA");

//        //模拟网络异常
//        System.out.println(10/0);

            String sql2 = "update user_table set balance = balance + 100 where user = ?";
            update1(conn, sql2, "BB");

            System.out.println("转账成功");

            //提交数据
            conn.commit();

        } catch (Exception e) {
            e.printStackTrace();
            //回滚数据
            try {
                conn.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }finally {
            JDBCUtils.closeResource(conn,null);
        }




    }

    //************************考虑数据库事物处理后的转账操作************************
    //考虑事物处理后的操作
    public static int update1(Connection conn, String sql, Object... args) {//sql中占位符的个数应该与可变形参的长度一致

        PreparedStatement ps = null;
        try {

            //1.预编译sql语句,返回PrepareStatement的实例
            ps = conn.prepareStatement(sql);

            //2.填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            //3.执行
            return ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.资源的关闭
            JDBCUtils.closeResource(null, ps);
        }

        return 0;


    }
    //通用的增删改操作  未考虑事物处理的操作
    public static int update(String sql, Object... args) {//sql中占位符的个数应该与可变形参的长度一致
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //1.获取数据库的连接
            conn = JDBCUtils.getConnection();

            //2.预编译sql语句,返回PrepareStatement的实例
            ps = conn.prepareStatement(sql);

            //3.填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            //4.执行
            return ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //修改
            try {
                conn.setAutoCommit(true);
            }catch (SQLException e) {
                 e.printStackTrace();
            }
            //5.资源的关闭
            JDBCUtils.closeResource(conn, ps);
        }

        return 0;


    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
动态代理可以实现数据库事务的管理,具体步骤如下: 1. 定义一个接口,该接口包含需要执行的数据库操作方法。 2. 实现该接口的类,该类用于执行具体的数据库操作。 3. 创建一个动态代理类,该类实现InvocationHandler接口,并重写invoke方法。 4. 在invoke方法中实现事务管理,即在执行数据库操作前开启事务,在操作后根据操作结果提交或回滚事务。 5. 在需要执行数据库操作的代码中,创建动态代理对象并调用接口方法。 下面是一个简单的示例代码: ```java public interface UserDao { void addUser(User user); void deleteUser(int userId); } public class UserDaoImpl implements UserDao { @Override public void addUser(User user) { // 执行添加用户操作 } @Override public void deleteUser(int userId) { // 执行删除用户操作 } } public class TransactionHandler implements InvocationHandler { private Object target; public TransactionHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Connection conn = null; PreparedStatement stmt = null; try { // 获取数据库连接 conn = getConnection(); // 开启事务 conn.setAutoCommit(false); // 执行目标方法 Object result = method.invoke(target, args); // 提交事务 conn.commit(); return result; } catch (Exception e) { // 回滚事务 conn.rollback(); throw e; } finally { // 关闭数据库连接 closeConnection(conn, stmt); } } private Connection getConnection() { // 获取数据库连接 } private void closeConnection(Connection conn, PreparedStatement stmt) { // 关闭数据库连接 } } public class Test { public static void main(String[] args) { UserDao userDao = new UserDaoImpl(); TransactionHandler handler = new TransactionHandler(userDao); UserDao proxy = (UserDao) Proxy.newProxyInstance( userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), handler); // 使用代理对象执行数据库操作 proxy.addUser(new User("张三", "123456")); proxy.deleteUser(1); } } ``` 在上面的示例代码中,TransactionHandler类是动态代理类,它实现了InvocationHandler接口,并重写了invoke方法。在invoke方法中,先获取数据库连接,然后开启事务,执行目标方法,根据操作结果提交或回滚事务,最后关闭数据库连接。 在Test类中,创建了UserDaoImpl对象和TransactionHandler对象,然后使用Proxy类的newProxyInstance方法创建了代理对象,并调用代理对象的方法执行数据库操作。由于使用了动态代理,所以在执行数据库操作时会自动进行事务管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值