web 学习笔记15-JDBC大数据 批处理 存储过程 事务

1、JDBC-大数据(LOB)的存取:

a.首先在数据新建个表,可以用下面的命令
    CREATE TABLE IF NOT EXISTS t_blob 
    (
        id INT PRIMARY KEY,
        image BLOB
    )
b.创建一个数据库的工具类
    写个dbcfg.properties在src目录下:
        driverClass=com.mysql.jdbc.Driver
        url=jdbc:mysql://localhost:3306/day16
        user=root
        password=root
        import java.sql.Connection;
        import java.sql.DriverManager;
        import java.sql.ResultSet;
        import java.sql.SQLException;
        import java.sql.Statement;
        import java.util.ResourceBundle;
        //专门用于数据库的工具类
        public class JdbcUtils {
            private static String driverClass = "" ;
            private static String url = "" ;
            private static String user = "" ;
            private static String password  = "";

            static{
                //我们将数据库的连接数据写在dfcfg.properties 文件中,方便配置
                ResourceBundle rb = ResourceBundle.getBundle("dbcfg") ;
                driverClass = rb.getString("driverClass") ;
                url = rb.getString("url") ;
                user = rb.getString("user") ;
                password = rb.getString("password") ;

                try {
                    Class.forName(driverClass) ;
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
            public static Connection getConnection(){
                try {
                    return DriverManager.getConnection(url, user, password) ;
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                return null ;
            }
            public static void release(ResultSet rs ,Statement stmt,Connection conn){
                if(rs != null){
                    try {
                        rs.close() ;
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if(stmt != null){
                    try {
                        stmt.close() ;
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                if(conn != null){
                    try {
                        conn.close() ;
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
c.我们写个测试类来测试存取功能:(存储图片)
        public class BlobTest {

        @Test
        public void testSave() throws Exception{
            Connection conn = JdbcUtils.getConnection() ;//获得链接对象
            //创建预处理命令对象
            PreparedStatement pstmt = conn.prepareStatement("insert into t1 values(?,?)") ;
            pstmt.setInt(1, 1) ;//指定?的值
            File file = new File("src/test.png") ;
            InputStream in = new FileInputStream(file) ;
            pstmt.setBinaryStream(2,in, (int)file.length()) ;//我们使用二进制存储,mysql里面需要强转下int

            //执行sql语句
            pstmt.executeUpdate() ;
            //释放资源
            JdbcUtils.release(null, pstmt, conn) ;
        }

        @Test
        public void testQuery() throws Exception{
            //获得链接对象
            Connection conn = JdbcUtils.getConnection() ;
            //创建预处理命令对象
            PreparedStatement pstmt = conn.prepareStatement("select * from t1") ;
            //执行sql语句
            ResultSet rs = pstmt.executeQuery() ;
            if(rs.next()){
                int id = rs.getInt("id") ;
                InputStream is = rs.getBinaryStream("image") ;
                //需要再建一个文件
                File f = new File("src/out.png") ;
                OutputStream os = new FileOutputStream(f) ;
                byte[] bs = new byte[1024] ;
                int b = 0 ;
                while((b = is.read(bs)) != -1){
                    os.write(bs,0,b) ;
                }
                is.close() ;
                os.close() ;
            }
            JdbcUtils.release(rs, pstmt, conn) ;
        }
    }

    注意:如果我们是存一个大的文本,就使用:
        File file = new File("src/test.txt") ;
        FileReader fr = new FileReader(file) ;
        pstmt.setCharacterStream(2,fr,(int)file.length()) ;

    因为我们存的大数据会比较慢,一般我们都是存文件的地址。

2、JDBC-批处理_一次性执行多条数据:

一次执行多条sql语句
a.通过Statement命令对象演示一个插入3条记录(速度快些)
    Statement stmt = conn.createStatement();
    String sql1 = "insert into t3 values(1,'name1',20)";
    String sql2 = "insert into t3 values(2,'name2',23)";
    String sql3 = "insert into t3 values(3,'name3',24)";

    // 将三条sql语句一起放入stmt对象中,一起发送到服务执行,在DBMS中会编译成一个逻辑执行单元,所以速度会更快一些
    stmt.addBatch(sql1);
    stmt.addBatch(sql2);
    stmt.addBatch(sql3);

    stmt.executeBatch();// 执行sql语句,返回的是一个数组
    JdbcUtils.release(null, stmt, conn);

b.通过PreparedStatement对象插入三条数据
    PreparedStatement pstmt = conn.prepareStatement("insert into t3 values(?,?,?)");
    // 指定?的值
    pstmt.setInt(1, 4);
    pstmt.setString(2, "name1");
    pstmt.setInt(3, 18);
    pstmt.addBatch();

    // 指定?的值
    pstmt.setInt(1, 5);
    pstmt.setString(2, "name2");
    pstmt.setInt(3, 17);
    pstmt.addBatch();

    // 指定?的值
    pstmt.setInt(1, 6);
    pstmt.setString(2, "name3");
    pstmt.setInt(3, 18);
    pstmt.addBatch();

    pstmt.executeBatch();// 执行sql语句
    JdbcUtils.release(null, pstmt, conn);// 释放资源

如果要插入大量的数据呢,1000条
        for (int i = 0; i < 1000; i++) {
            // 指定?的值
            pstmt.setInt(1, i);
            pstmt.setString(2, "name" + i);
            pstmt.setInt(3, i);

            pstmt.addBatch();//这个是将多条数据放到一起执行

            if(i%200 == 0){//200条一起执行
                pstmt.executeBatch() ;//执行sql语句
                pstmt.clearBatch() ;//一定要清空缓存
            }   
        }
        //为了防止缓存中还有sql没有执行,在for外面应当再次 执行sql语句
        pstmt.executeBatch();

        1000条数据插入大概花了1分钟左右

3、JDBC-存储过程:

类似方法,存储过程形参可以有默认值,可以返回多个值
    #sql语句,定义一个无参的存储过程
        delimiter $$ //定义一个结束标识符
		create procedure pro1()
		begin
			select * from mytable ;
		end ;
		$$
        delimiter ;//修改回来
java调用方法:
        /演示JDBC调用存储过程,使用的是CallableStatement
        public class ProcedureTest {
            //执行不带返回值的存储过程没有任何意义
            @Test
            public void testPro1() throws Exception {
                Connection conn = JdbcUtils.getConnection();// 获得链接对象
                // 创建执行存储过程的命令对象
                CallableStatement cstmt = conn.prepareCall("{call pro2(?)}") ;
                cstmt.setInt(1, 1) ;//指定?的值
                cstmt.execute() ;//执行存储过程
                JdbcUtils.release(null, cstmt, conn);// 释放资源
            }

            @Test
            public void testPro2() throws Exception {
                Connection conn = JdbcUtils.getConnection();// 获得链接对象
                // 创建执行存储过程的命令对象
                CallableStatement cstmt = conn.prepareCall("{call pro2(?,?)}") ;
                cstmt.setInt(1, 1) ;//指定?的值
                cstmt.registerOutParameter(2, Types.VARCHAR) ;//指定第二个?是输出参数
                cstmt.execute() ;//执行存储过程
                String name = cstmt.getString(2) ;//获得返回值
                JdbcUtils.release(null, cstmt, conn);// 释放资源
            }
        }

    好处就是java代码里面不用写sql语句,我们后面数据库变了,sql语句也会变,我们写只需要修改存储过程就行
    不用修改代码了。还有一种方式就是mybatis,sql语句写在xml文件中。

4、JDBC-事务执行:

一组命令,要么全部成功,要么全部失败。
sql语句:
    开始事务  start transaction;
    提交事务:commit;
    回滚:rollback;
例如:
        //采用事务处理转账失败的情况
        @Test
        public void testTransaction1() throws Exception {
            Connection conn = JdbcUtils.getConnection();// 获得链接对象

            PreparedStatement pstmt = null ;
            PreparedStatement pstmt1 = null ;

            conn.setAutoCommit(false) ;//让数据库不要自动提交事务
            try{
                pstmt = conn.prepareStatement("update bank set money = money -? where id = ?") ;
                pstmt.setFloat(1, 2000) ;
                pstmt.setInt(2, 1) ;
                int n = pstmt.executeUpdate() ;

                System.out.println(10/2);

                pstmt1 = conn.prepareStatement("update bank set money = money + ? where id = ?") ;
                pstmt1.setFloat(1, 2000) ;
                pstmt1.setInt(2, 2) ;
                int n1 = pstmt1.executeUpdate() ;

                conn.commit() ;//手动进行提交,体现一致性
            }catch(Exception  e){
                conn.rollback() ;//让事务进行回滚
            }
            // 释放资源
            JdbcUtils.release(null, pstmt, conn);
            JdbcUtils.release(null, pstmt1, conn);
        }
    注意:一定要在一个连接里面提交事务。

5、事务的隔离级别:

不考虑事务的隔离级别会导致什么问题?
1、脏读:指一个事务到读到另外一个事务中未提交的数据。
2、不可重复读:指一个事务读到另外一个事务执行update的语句的结果(已提交)
3、虚读:指一个事务读到另外一个事务执行的insert的语句的结果(已提交)

MySQL中支持的事务隔离级别:
READ UNCOMMITTED:脏读、不可重复读、虚读有可能发生。
READ COMMITTED:防止脏读的发生;不可重复读、虚读有可能发生。
REPEATABLE READ:防止脏读、不可重复读的发生;虚读有可能发生。(MySQL中默认)
SERIALIZABLE:防止脏读、不可重复读、虚读。

随着级别的增高,数据越安全,但效率越低。
查看当前的事务隔离级别:select @@tx_isolation;//查询默认的级别是 REPEATABLE-READ
更改当前的事务隔离级别:set transaction isolation level 四个级别; 

6、锁机制

共享锁:一个事务开启时,使用了共享锁,其他事务也可以设置共享锁。读数据是没有问题的。
select * from table1 lock in share mode;//给table1加共享锁,作用不大

排它锁:一个事务开启时,使用了排他锁,其他事务只有等待
update insert 等语句会自动加排他锁
select * from table2 for update;
例如:
    开启一个事务, start transaction;
    加个排他锁,select * from table2 for update;
    在另外一个cmd中,开启一个事务, start start transaction;
    此时你在这个cmd中执行insert,会等待之前cmd中的事务提交才响应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值