事务

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

事务ACID特性

 原子性(Atomicity)

原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

 一致性(Consistency)

事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

 隔离性(Isolation)

事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

 持久性(Durability)

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

事务的特性:
    原子性,是一个最小逻辑操作单元 !
    一致性,事务过程中,数据处于一致状态。
    持久性, 事务一旦提交成功,对数据的更改会反映到数据库中。
    隔离性, 事务与事务之间是隔离的。

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

案列: 张三给李四转账

没有使用事务
// 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);
    }

}

批处理

批量执行sql语句!

设计:
AdminDao
    Public  void  save(List<Admin list){    // 目前用这种方式
        // 循环
        // 保存  (批量保存)
    }

    Public  void  save(Admin  admin ){
        // 循环
        // 保存
    }

技术:

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

实现:

Admin.java         实体类封装数据
AdminDao.java      封装所有的与数据库的操作
App.java           测试

Admin

/实体类封装数据
public class Admin {

private String userName;
private String pwd;
public String getUserName() {
    return userName;
}
public void setUserName(String userName) {
    this.userName = userName;
}
public String getPwd() {
    return pwd;
}
public void setPwd(String pwd) {
    this.pwd = pwd;
}

}

AdminDao

// 封装所有的与数据库的操作
public class AdminDao {

// 全局参数
private Connection con;
private PreparedStatement pstmt;
private ResultSet rs;

// 批量保存管理员
public void save(List<Admin> list) {
    // SQL
    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);
    }
}
}

插入数据,获取自增长值

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);
    }
}
}

Jdbc中大文本类型的处理

Oracle中大文本数据类型,
Clob    长文本类型   (MySQL中不支持,使用的是text)
Blob    二进制类型

 MySQL数据库,
Text    长文本类型
Blob    二进制类型

App_text(处理长文本类型)

public class App_text {

// 全局参数
private Connection con;
private Statement stmt;
private PreparedStatement pstmt;
private ResultSet rs;


@Test
// 1. 保存大文本数据类型   ( 写longtext)
public void testSaveText() {
    String sql = "insert into test(content) values(?)";
    try {
        // 连接
        con = JdbcUtil.getConnection();
        // pstmt 对象
        pstmt = con.prepareStatement(sql);
        // 设置参数
        // 先获取文件路径
        String path = App_text.class.getResource("tips.txt").getPath();
        FileReader reader = new FileReader(new File(path));
        pstmt.setCharacterStream(1, reader);

        // 执行sql
        pstmt.executeUpdate();

        // 关闭
        reader.close();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.closeAll(con, pstmt, null);
    }
}

@Test
// 2. 读取大文本数据类型   ( 读longtext)
public void testGetAsText() {
    String sql = "select * from  test;";
    try {
        // 连接
        con = JdbcUtil.getConnection();
        // pstmt 对象
        pstmt = con.prepareStatement(sql);
        // 读取
        rs = pstmt.executeQuery();
        if (rs.next()) {
            // 获取长文本数据, 方式1:
            //Reader r = rs.getCharacterStream("content");

            // 获取长文本数据, 方式2:
            System.out.print(rs.getString("content"));
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.closeAll(con, pstmt, null);
    }
}
}

App_blob(处理二进制类型)

public class App_blob {

// 全局参数
private Connection con;
private Statement stmt;
private PreparedStatement pstmt;
private ResultSet rs;


@Test
// 1. 二进制数据类型   ( 写longblob)
public void testSaveText() {
    String sql = "insert into test(img) values(?)";
    try {
        // 连接
        con = JdbcUtil.getConnection();
        // pstmt 对象
        pstmt = con.prepareStatement(sql);
        // 获取图片流
        InputStream in = App_text.class.getResourceAsStream("7.jpg");
        pstmt.setBinaryStream(1, in);

        // 执行保存图片
        pstmt.execute();

        // 关闭
        in.close();

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.closeAll(con, pstmt, null);
    }
}

@Test
// 2. 读取大文本数据类型   ( 读longblob)
public void testGetAsText() {
    String sql = "select img from  test where id=2;";
    try {
        // 连接
        con = JdbcUtil.getConnection();
        // pstmt 对象
        pstmt = con.prepareStatement(sql);
        // 读取
        rs = pstmt.executeQuery();
        if (rs.next()) {
            // 获取图片流
            InputStream in = rs.getBinaryStream("img");
            // 图片输出流
            FileOutputStream out = new FileOutputStream(new File("c://1.jpg"));
            int len = -1;
            byte b[] = new byte[1024];
            while ((len = in.read(b)) != -1) {
                out.write(b, 0, len);
            }
            // 关闭
            out.close();
            in.close();
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.closeAll(con, pstmt, null);
    }
}
}
posted on 2018-05-18 16:04  NE_STOP  阅读(1)  评论(0编辑  收藏  举报  来源