Java进阶学习第八天(批处理、插入数据获取自增长值、事务)

一、批处理

1、Statement批处理相关方法
void addBatch(String sql):添加批处理
void clearBatch():清空批处理
int[] executeBatch():执行批处理

2、实现:
Admin.java:实体类封装数据

public class Admin {
    private String userName;
    private String pwd;
}

AdminDao.java:封装所有的与数据库的操作

public class AdminDao { 
    // 全局参数
    private Connection con;
    private PreparedStatement pstmt;
    private ResultSet rs;

    // 批量保存管理员
    public void save(List<Admin> list) {
        String sql = "INSERT INTO admin(userName,pwd) values(?,?)";
        try {
            // 获取连接
            con = JdbcUtil.getConnection();
            // 创建stmt 
            pstmt = con.prepareStatement(sql);// 预编译SQL语句
            for (int i=0; i<list.size(); i++) {
                Admin admin = list.get(i);
                // 设置参数
                pstmt.setString(1, admin.getUserName());
                pstmt.setString(2, admin.getPwd());
                // 添加批处理
                pstmt.addBatch();//不需要传入SQL
                // 测试:每5条执行一次批处理
                if (i % 5 == 0) {
                    // 批量执行 
                    pstmt.executeBatch();
                    // 清空批处理
                    pstmt.clearBatch();
                }   
            }
            // 批量执行 
            pstmt.executeBatch();
            // 清空批处理
            pstmt.clearBatch(); 
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.closeAll(con, pstmt, rs);
        }
    }
}

App.java:测试

public class App {
    // 测试批处理操作
    @Test
    public void testBatch() throws Exception {
        // 模拟数据
        List<Admin> list = new ArrayList<Admin>();
        for (int i=1; i<21; i++) {
            Admin admin = new Admin();
            admin.setUserName("Jack" + i);
            admin.setPwd("888" + i);
            list.add(admin);
        }   
        // 保存
        AdminDao dao = new AdminDao();
        dao.save(list);
    }
}

3、注意:如果一次执行的记录数过多,最好按10或100个条件执行一次操作,并清空批处理,目的是为了避免内存溢出。

二、插入数据获取自增长值

public class EmpDao {
    private Connection con;
    private PreparedStatement pstmt;
    private ResultSet rs;
    // 保存员工,同时保存关联的部门
    public void save(Employee emp){ 
        // 保存部门
        String sql_dept = "insert into dept(deptName) values(?)";
        // 保存员工
        String sql_emp = "INSERT INTO employee (empName,dept_id) VALUES (?,?)";
        // 部门id
        int deptId = 0; 
        try {
            // 连接
            con = JdbcUtil.getConnection();
            /*****保存部门,获取自增长*******/
            // 【一、需要指定返回自增长标记】
            pstmt = con.prepareStatement(sql_dept,Statement.RETURN_GENERATED_KEYS);
            // 设置参数
            pstmt.setString(1, emp.getDept().getDeptName());
            // 执行
            pstmt.executeUpdate();

            // 【二、获取上面保存的部门子增长的主键】
            rs =  pstmt.getGeneratedKeys();
            // 得到返回的自增长字段
            if (rs.next()) {
                deptId = rs.getInt(1);
            }   
            // 保存员工
            pstmt = con.prepareStatement(sql_emp);
            // 设置参数
            pstmt.setString(1, emp.getEmpName());
            pstmt.setInt(2, deptId);
            pstmt.executeUpdate();  
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.closeAll(con, pstmt, rs);
        }
    }
}

三、事务

1、基本概念
事务使指一组最小逻辑操作单元,里面有多个操作组成。 组成事务的每一部分必须要同时提交成功,如果有一个操作失败,整个操作就回滚。

2、事务ACID特性
① 原子性(Atomicity):是一个最小逻辑操作单元
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
② 一致性(Consistency):事务过程中,数据处于一致状态
事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
③ 隔离性(Isolation):事务与事务之间是隔离的
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
④ 持久性(Durability):事务一旦提交成功,对数据的更改会反映到数据库中
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

3、Connection技术
void setAutoCommit(boolean autoCommit) ; :设置事务是否自动提交,如果设置为false,表示手动提交事务
void commit() ();:手动提交事务
void rollback();:回滚(出现异常时候,所有已经执行成功的代码需要回退到事务开始前的状态)
Savepoint setSavepoint(String name);

4、转账案列
UPDATE account SET money=money-1000 WHERE accountName='张三';
UPDATE account SET money=money+1000 WHERE accountName='李四';

public class AccountDao {
    // 全局参数
    private Connection con;
    private PreparedStatement pstmt;

    // 1. 转账,没有使用事务
    public void trans1() {
        String sql_zs = "UPDATE account SET money=money-1000 WHERE accountName='张三';";
        String sql_ls = "UPDATE account SET money=money+1000 WHERE accountName='李四';";
        try {
            con = JdbcUtil.getConnection(); // 默认开启的隐式事务
            con.setAutoCommit(true);
            /*** 第一次执行SQL ***/
            pstmt = con.prepareStatement(sql_zs);
            pstmt.executeUpdate();
            /*** 第二次执行SQL ***/
            pstmt = con.prepareStatement(sql_ls);
            pstmt.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.closeAll(con, pstmt, null);
        }
    }

    // 2. 转账,使用事务
    public void trans2() {
        String sql_zs = "UPDATE account SET money=money-1000 WHERE accountName='张三';";
        String sql_ls = "UPDATE1 account SET money=money+1000 WHERE accountName='李四';";
        try {
            con = JdbcUtil.getConnection(); // 默认开启的隐式事务
            // 一、设置事务为手动提交
            con.setAutoCommit(false);
            /*** 第一次执行SQL ***/
            pstmt = con.prepareStatement(sql_zs);
            pstmt.executeUpdate();
            /*** 第二次执行SQL ***/
            pstmt = con.prepareStatement(sql_ls);
            pstmt.executeUpdate();
        } catch (Exception e) {
            try {
                // 二、 出现异常,需要回滚事务
                con.rollback();
            } catch (SQLException e1) {
            }
            e.printStackTrace();
        } finally {
            try {
                // 三、所有的操作执行成功, 提交事务
                con.commit();
                JdbcUtil.closeAll(con, pstmt, null);
            } catch (SQLException e) {
            }
        }
    }

    // 3. 转账,使用事务,并回滚到指定的代码段
    public void trans() {
        // 定义个标记
        Savepoint sp = null;    
        // 第一次转账
        String sql_zs1 = "UPDATE account SET money=money-1000 WHERE accountName='张三';";
        String sql_ls1 = "UPDATE account SET money=money+1000 WHERE accountName='李四';";
        // 第二次转账
        String sql_zs2 = "UPDATE account SET money=money-500 WHERE accountName='张三';";
        String sql_ls2 = "UPDATE1 account SET money=money+500 WHERE accountName='李四';";
        try {
            con = JdbcUtil.getConnection(); // 默认开启的隐式事务
            con.setAutoCommit(false);       // 设置事务手动提交
            /*** 第一次转账 ***/
            pstmt = con.prepareStatement(sql_zs1);
            pstmt.executeUpdate();
            pstmt = con.prepareStatement(sql_ls1);
            pstmt.executeUpdate();
            // 回滚到这个位置
            sp = con.setSavepoint();    
            /*** 第二次转账 ***/
            pstmt = con.prepareStatement(sql_zs2);
            pstmt.executeUpdate();
            pstmt = con.prepareStatement(sql_ls2);
            pstmt.executeUpdate();
        } catch (Exception e) {
            try {
                // 回滚 (回滚到指定的代码段)
                con.rollback(sp);
            } catch (SQLException e1) {
            }
            e.printStackTrace();
        } finally {
            try {
                // 提交
                con.commit();
            } catch (SQLException e) {
            }
            JdbcUtil.closeAll(con, pstmt, null);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Mr_GaoYang/article/details/82532508