Java——JDBC小结(5)

1.事物

关于事物的概念及原理有好多好多,但我的理解就是一句话,要保持一个整体性,就是一个事,要分成几个步骤去完成,但是只有这几个步骤都做完了才是一个完整的事。这里面最简单的示例就是模拟银行的取款与存款了,我直接给出这个示例代码然后加以分析

 1     @Test
 2     public void test2(){
 3         String payId="00001";
 4         String recId="00002";
 5         double mny=1000;
 6         Connection conn=null;
 7         try {
 8             conn=DBUtil.getConnection();
 9             String sql="select *from accounts_jiawen "
10                     + "where id=?";
11             PreparedStatement ps=conn.prepareStatement(sql);
12             ps.setString(1, recId);
13             ResultSet rs=ps.executeQuery();
14             if(!rs.next()){
15                 System.out.println("收款帐号不存在");
16                 throw new SQLException("收款帐号不存在");
17             }            
18             //记录收款方的余额
19             double recMoney=rs.getDouble("money");
20             
21             //设置手动管理事务
22             conn.setAutoCommit(false);
23             
24             //2.验证付款方余额够不够
25             sql="select * from accounts_jiawen "
26                     + "where id=?";
27             ps=conn.prepareStatement(sql);
28             ps.setString(1, payId);
29             rs=ps.executeQuery();
30             rs.next();
31             double payMoney=rs.getDouble("money");
32             if(payMoney<mny){
33                 System.out.println("余额不足");
34                 throw new SQLException("余额不足");
35             }
36             
37         
38             
39             //3.付款方余额减少n元
40             sql="update accounts_jiawen set "
41                     + "money=? where id=?";
42             ps=conn.prepareStatement(sql);
43             ps.setDouble(1, payMoney-mny);
44             ps.setString(2, payId);
45             ps.executeQuery();
46             
47             //假设此处有一个错误
48 //            Integer.valueOf("abc");
49             //4.收款方加n元
50             sql="update accounts_jiawen set "
51                     + "money=? where id=?";
52             ps=conn.prepareStatement(sql);
53             ps.setDouble(1, recMoney+mny);
54             ps.setString(2, recId);
55             ps.executeQuery();
56             //当转账流程正常结束时统一提交事物
57             conn.commit();
58         } catch (Exception e) {
59             //当转账过程发生异常时回滚事务
60             try {
61                 conn.rollback();
62             } catch (SQLException e1) {
63                 // TODO Auto-generated catch block
64                 e1.printStackTrace();
65                 throw new RuntimeException("回滚");
66             }
67             e.printStackTrace();
68             throw new RuntimeException("wrong",e);
69         }finally{
70             DBUtil.close(conn);
71         }
72     }

 

首先,我们模拟两个银行的账号,一个给另一个汇款,首先我们要先查询一下收款人的信息,这和符合世纪逻辑,因为我们要知道收款人是否存在,同样是做一个select查询语句,方法依然使用的是前述的ParperdStatement,设置占位符的方法,判断收款人是否存在,并记录下收款方的现在余额,以便在收到钱后做一个累加。

然后重点来了,在第22行,这就是手动管理一个事物,将自动管理事物关闭,这样以上的代码就不是意见完整的事,否则他就是完整的一件事,而不会等待下面的过程,但实际上收款与汇款整体才能算上一件事,因为这涉及到两个人的账户金额变动问题,你不能只考虑其中一个人的金额变化,而将它设置为false以后上面的过程就会一起等待下面的过程。第二部是验证付款方的余额,判断是否够转。后面的过程就是收付双方金额的变动,如果你不把事物设置为手动的话,在第四步上面模拟一个代码打断一下下面代码的执行,那么后面的金额将发生错误。这里面还要说明的是conn.commit()是统一提交事务,而conn.rollback()为回滚

2.批处理

见名知意,就是集中到一起发送一组SQL,好处也就是效率更高,降低了数据库和程序之间的网络调用,直接给出示例代码:

    @Test
    public void test3(){
        Connection conn=null;
        try {
            conn=DBUtil.getConnection();
            conn.setAutoCommit(false);
            
            //批量发送数据的前提是他们的SQL一样
            String sql="insert into emp_jiawenzhe values("
                    + " emp_jiawenzhe_w.nextval,?,?,?,?,?,?,?)";
            PreparedStatement ps =conn.prepareStatement(sql);
            for(int i=1;i<=108;i++){
                ps.setString(1, "好汉"+i);
                ps.setString(2, "打劫");
                ps.setInt(3, 0);
                ps.setDate(4, null);
                ps.setDouble(5, 1000.0);
                ps.setDouble(6, 8000.0);
                ps.setInt(7, 3);
                //将本条数据存到ps内
                ps.addBatch();
                //每30次批量发送一次数据
                if(i%30==0){
                    ps.executeBatch();
                    //清除缓存的数据
                    ps.clearBatch();
                }
            }
            //余下的数据单独发送一次
            ps.executeBatch();
            
            conn.commit();
        } catch (SQLException e) {
            try {
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
            throw new RuntimeException("批量添加员工失败",e);
        }finally{
            DBUtil.close(conn);
        }
        
        
    }

这是一个批量插入员工的示例,首先要说明的是,批量发送SQL,前提是他们的SQL要一致,就是干的都是同样的一种事,在开始进行批处理之前,先要把事物的设置设置为手动提交,下一步就是建立SQL的变参数模型,比如说这里面我建立的是一个插入的模型,下面的for循环完全是为了省事,做出了插入108条数据的写法,当然你也可以逐一写

下面我将说明一下addBatch()这个方法,我们在写了108条数据并不是直接就写到了数据库中,他同样是要调用ParperdStatement的发送方法,但这就不是excuteQuery,写出来的东西要先放到缓存中,然后从缓存中拿到一部分数据发送数据库,再将发送完了的SQL清除缓存,下面做的是每30条发送一次的代码,调用excuteBatch发送,然后调用clearBatch清除缓存,当然最后剩下的要再一次调用excuteBatch一次性发送走,最后不要忘记提交,因为之前已经设置成了手动提交。

 3.返回自动主键

首先对于这块我认为不太好理解,用起来似乎也没有上面那么简单,接下来同样是引用一个示例加以说明:

这个示例是这个样子的,首先要有两张表,一张是部门表,一张是员工表,这两个表是关联的,即主表部门表的主键deptno在从表的列中也有出现,并成为从表的外键,当对主表进行插入的时候,能将从表的信息一并插入

 1 @Test
 2     public void test4(){
 3         //假设要添加的部门数据如下
 4         String dname ="财务部";
 5         String loc="北京";
 6         //假设要添加员工的数据如下
 7         String ename="张三";
 8         String job="经理";
 9         int mgr=0;
10         double sal=8000.0;
11         double comm=2000.0;
12         
13         String ename2="李四";
14         String job2="经理";
15         int mgr2=0;
16         double sal2=5000.0;
17         double comm2=500.0;
18         
19         Connection conn=null;
20         try {
21             conn=DBUtil.getConnection();
22             conn.setAutoCommit(false);
23             //先添加部门
24             String sql ="insert into depts_jiawen "
25                     + " values(depts_seq_jiawen.nextval,?,?) " ;
26             //参数二是一个数组存的是希望被ps记住的字段名字
27             PreparedStatement ps=conn.prepareStatement(sql,new String[]{"deptno"});
28             ps.setString(1, dname);
29             ps.setString(2, loc);
30             ps.executeUpdate();
31             
32             //从ps中获取它之前记录的字段值
33             //返回的结果集中只有一种数据
34             //存的就是记录那些字段的值
35             ResultSet rs=ps.getGeneratedKeys();
36             rs.next();
37             int deptno=rs.getInt(1);
38             
39             //再添加员工
40             sql="insert into emp_jiawenzhe values( "
41                     + "depts_seq_jiawen.nextval,?,?,?,?,?,?,?) ";
42             ps=conn.prepareStatement(sql);
43             ps.setString(1, ename);
44             ps.setString(2, job);
45             ps.setInt(3, mgr);
46             ps.setDate(4, null);
47             ps.setDouble(5, sal);
48             ps.setDouble(6, comm);
49             ps.setInt(7, deptno);
50             ps.executeUpdate();
51             
52             ps=conn.prepareStatement(sql);
53             ps.setString(1, ename2);
54             ps.setString(2, job2);
55             ps.setInt(3, mgr2);
56             ps.setDate(4, null);
57             ps.setDouble(5, sal2);
58             ps.setDouble(6, comm2);
59             ps.setInt(7, deptno);
60             ps.executeUpdate();
61             
62             conn.commit();
63             
64         } catch (SQLException e) {
65             try {
66                 conn.rollback();
67             } catch (SQLException e1) {
68                 // TODO Auto-generated catch block
69                 e1.printStackTrace();
70             }
71             e.printStackTrace();
72             throw new RuntimeException("wrong",e);
73         }finally{
74             DBUtil.close(conn);
75         }
76     }

这里面可以看到ParperdStatement中传入了两个参数,第一个和之前一样,是要执行的SQL,而第二个参数是一个字符串数组,他是希望被记住的字段名字,我的理解就是那个外键字段放到里面,为了后面取到这个外键的值传入到从表中进行更新,然后调用了getGeneratedKeys()获得了这些主键的结果集,再用int deptno=rs.getInt(1);得到对应字段的值,对于这块我实在不能明朗的解释清楚,目前我也只能说先这么记住吧,而后面的插入从表就是一个批处理操作,与前述相同。

4.分页

分页就是对于一个更庞大的数据表当我们不希望看到整表时,可以分成几段呈现,这个内容就是一个固定的模式,有固定的分页公式,一目了然,用的时候直接拿过来使用就好了

示例代码:

 1     @Test
 2     public void test5(){
 3         int size=10;
 4         int page=2;
 5         
 6         Connection conn=null;
 7         try {
 8             conn=DBUtil.getConnection();
 9             String sql="select * from( "
10                     + "select e.*,rownum r from ( "
11                     + "select * from emp_jiawenzhe "
12                     + "order by empno "
13                     + ") e "
14                     + ") where r between ? and ?";
15             PreparedStatement ps=conn.prepareStatement(sql);
16             ps.setInt(1, (page-1)*size+1);
17             ps.setInt(2, size*page);
18             ResultSet rs=ps.executeQuery();
19             while (rs.next()) {
20                 System.out.println(rs.getInt("empno")+","+rs.getString("ename"));
21                 
22             }
23         } catch (SQLException e) {
24         
25             e.printStackTrace();
26             throw new RuntimeException("wrong",e);
27         }finally{
28             DBUtil.close(conn);
29         }
30     }

page和size分别是分几页,每页有几个,分页的SQL写法是数据库内容,我将在数据库基本SQL使用中提到,这里面暂时先这么写着,后面的内容也就很清楚了!

未完待续!

转载于:https://www.cnblogs.com/jwz-bk/p/5487570.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值