数据库Mysql拔高: 存储过程、事务、 



 一、获取数据库自动生成的主键 

             主键的值最好由自己的程序来维护 

             注: 只对insert有效 

          

         例: 

         ------------------------------------------------------------------------------- 

         create database day16; 

         use day16; 

         create table t1( 

                 id int primary key auto_increment, 

                 name varchar(100) 

         );       

         ------------------------------------------------------------------------------- 

         // 获取数据库自动生成的主键  

       public class GetDBGenKeyDemo { 

               @Test 

               public void test(){ 

                       Connection conn = null; 

                       PreparedStatement stmt = null; 

                       ResultSet rs = null; 

                       try{ 

                               conn = JdbcUtil.getConnection(); 

                               // 获取数据库插入的主键的值 : 第二个参数默认可以省略: 注: 此参数仅对insert操作有效 

                         //  stmt = conn.prepareStatement("insert into t1 (name) values(?)", Statement.RETURN_GENERATED_KEYS);   

                               stmt = conn.prepareStatement("insert into t1 (name) values(?)"); 

                               stmt.setString(1, "gfy"); 

                               stmt.executeUpdate(); 

                               // 以下就是获取数据库生成的主键的值 

                               rs = stmt.getGeneratedKeys(); // 一行一列 

                               if(rs.next()){ 

                                       System.out.println(rs.getInt(1)); 

                               } 

                       }catch(Exception e){ 

                               e.printStackTrace(); 

                       }finally{ 

                               JdbcUtil.release(rs, stmt, conn); 

                       } 

                 } 

         ------------------------------------------------------------------------------- 

            

 二、存储过程(详解参考后面的oracle) 

           delimiter $$    重新定义分界符        

            

           例: 

           ****************************************************************** 

           创建存储过程:   用字符串welcome---与传入的参数进行连接后返回 

           delimiter $$    // 修改分界符为$$ 

           CREATE PROCEDURE demoSp(IN inputParam VARCHAR(255), INOUT inOutParam varchar(255))   

           BEGIN  

                  SELECT CONCAT('welcome---', inputParam) into inOutParam; 

           END $$ 

           delimiter ; 
    // 还原分界符为; 

           ****************************************************************** 

           调用存储过程 

           public class InvokeProcedureDemo { 

                   @Test 

                   public void test(){ 

                           Connection conn = null; 

                           CallableStatement stmt = null;  // 调用存储过程的类 

                           ResultSet rs = null; 

                           try{ 

                                   conn = JdbcUtil.getConnection(); 

                                   // 书写格式 

                                   stmt = (CallableStatement) conn.prepareCall("{call demoSp(?,?)}"); 

                                   // 存储过程的输入参数,给值即可; 输出参数: 要告诉它参数的类型 

                                   stmt.setString(1, "to shanghai"); 

                                   stmt.registerOutParameter(2, Types.VARCHAR); 

                                   // 调用存储过程 

                                   stmt.execute(); 

                                   // 得到存储过程中的值并输出 

                                   String value = stmt.getString(2); 

                                   System.out.println(value); 

                           }catch(Exception e){ 

                                   e.printStackTrace(); 

                           }finally{ 

                                   JdbcUtil.release(rs, stmt, conn); 

                           } 

                   }            

           } 

           ****************************************************************** 



 三、事务入门 

           事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功 

           TPL:事务控制语句 

                     start transaction:开启一次事务 

                     rollback:  回滚 

                     commit:提交事务 



           JDBC中与事务有关的方法: 

                   Connection.setAutoCommit(boolean b) 

                   Connection.rollback() 

                   Connection.rollback(Savepoint sp) 

                   Connection.commit(); 



           例: 

           *************************************************************************** 

           use day16; 

           create table account( 

                   id int primary key auto_increment, 

                   name varchar(40), 

                   money float 

           )character set utf8 collate utf8_general_ci; 

           insert into account(name,money) values('aaa',1000); 

           insert into account(name,money) values('bbb',1000); 

           insert into account(name,money) values('ccc',1000); 

           *************************************************************************** 

           public class TransactionDemo { 

 

                   @Test // aaa给bbb转账100 

                   public void test1(){ 

                           Connection conn = null; 

                           PreparedStatement stmt = null; 

                           ResultSet rs = null; 

                           try{ 

                                   conn = JdbcUtil.getConnection(); 

                                   //事务是默认开启的 

                                   // 手工开启事务 

                                   conn.setAutoCommit(false); 
 // 事务的开始: 相当于: start transaction 

                                    

                                   // 在同一事务中的语句 

                                   stmt = conn.prepareStatement("update account set money=money-100 where name='aaa'"); 

                                   stmt.executeUpdate(); 

                             // 
 int i = 1/0; 

                                   stmt = conn.prepareStatement("update account set money=money+100 where name='bbb'"); 

                                   stmt.executeUpdate(); 

                                    

                                   conn.commit();           // 提交事务: commit 

                           }catch(Exception e){ 

                                   e.printStackTrace(); 

                                   try{ 

                                           conn.rollback();  // 事务的回滚 

                                   }catch (SQLException e1){ 

                                           e1.printStackTrace(); 

                                   } 

                           }finally{ 

                                   JdbcUtil.release(rs, stmt, conn); 

                           } 

                   } 

                    

                   @Test // aaa转给bbb 100,  bbb转给ccc 100 

                   public void test2(){ 

                           Connection conn = null; 

                           PreparedStatement stmt = null; 

                           ResultSet rs = null; 

                           Savepoint sp = null; 

                           try{ 

                                   conn = JdbcUtil.getConnection(); 

                                   conn.setAutoCommit(false); 

                                    

                                   stmt = conn.prepareStatement("update account set money=money-100 where name='aaa'"); 

                                   stmt.executeUpdate(); 

                                   stmt = conn.prepareStatement("update account set money=money+100 where name='bbb'"); 

                                   stmt.executeUpdate(); 

                                   sp = conn.setSavepoint(); 
 // 设置回滚点 

                                   stmt = conn.prepareStatement("update account set money=money-100 where name='bbb'");   

                                   stmt.executeUpdate(); 

                             // 
 int i = 1/0; 
 // bbb给ccc转账的时候出现异常 此时要回滚  

                                   stmt = conn.prepareStatement("update account set money=money+100 where name='ccc'"); 

                                   stmt.executeUpdate();                            

                           }catch(Exception e){ 

                                   e.printStackTrace(); 

                                   try { 

                                           conn.rollback(sp);  // 回滚到设置的回滚点sp 

                                   } catch (SQLException e1) { 

                                           e1.printStackTrace(); 

                                   } 

                           }finally{ 

                                   try { 

                                           conn.commit(); 

                                   } catch (SQLException e) { 

                                           e.printStackTrace(); 

                                   } 

                             JdbcUtil.release(rs, stmt, conn); 

                           }                   

                   } 

              

           } 

           *************************************************************************** 





 四、事务的特性(隔离级别) 

           A:原子性。说明事务是一个不可分割的单位。 

           C:一致性.事务必须使数据库从一个一致性状态变换到另外一个一致性状态.(比如转账) 

          *I:隔离性。一个事务不能被其他事务打扰。 

           D:持久性。事务一旦提交,就应该被永久保存起来。 



           如果不考虑事务的隔离级别,会出现以下“不正确”的情况: 

                 脏读:指一个事务读到了另一个事务中未提交的数据。  

                 不可重复读:针对一条记录的,同一条记录前后不一样 

                 虚读(幻读):针对一张表,前后读到的记录条数不一样。 



           MySQL中控制事务隔离级别的语句: 

                     select @@tx_isolation;     //查看当前的事务隔离级别 

                     set transaction isolation level 你的级别(四种之一);//设置隔离级别 



           隔离级别的分类: 

                     READ UNCOMMITTED:脏读、不可重复读、虚读都有可能发生。 

                     READ COMMITTED:能避免脏读,不可重复读、虚读都有可能发生。 

                     REPEATABLE READ:能避免脏读、不可重复度,虚读都有可能发生。 

                     SERIALIZABLE:能避免脏读、不可重复度、虚读。 

                      

           注: 事务的隔离级别必须用在事务之中; 

                   一定要在事务开启之前设置事务的隔离级别,否则无效 

            

           例: 

           ********************************************************************************** 

           脏读的演示: 

           public class TransactionIsolationDemo { 

                   @Test 

                   public void test(){ 

                           Connection conn = null; 

                           PreparedStatement stmt = null; 

                           ResultSet rs = null; 

                           try{ 

                                   conn = JdbcUtil.getConnection(); 

                                   // 设置事务的隔离级别  注: 一定要在事务开启之前设置事务的隔离级别,否则无效 

                                   conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); 

                                   conn.setAutoCommit(false); 

                                   stmt = conn.prepareStatement("select * from account where name='aaa'"); 

                                   rs = stmt.executeQuery(); 

                                   if(rs.next()){ 

                                           System.out.println("开始时的余额:"+rs.getString("money")); 

                                   } 

                                   Thread.sleep(20*1000);           // 此时开启另一个dos,模拟多线程操作 

                                   stmt = conn.prepareStatement("select * from account where name='aaa'"); 

                                   rs = stmt.executeQuery(); 

                                   if(rs.next()){ 

                                           System.out.println("别人未提交事务时的余额:"+rs.getString("money")); 

                                   } 

                           }catch(Exception e){ 

                                   e.printStackTrace(); 

                                   try { 

                                           conn.rollback(); 

                                   } catch (SQLException e1) { 

                                           e1.printStackTrace(); 

                                   } 

                           }finally{ 

                                   try { 

                                           conn.commit(); 

                                   } catch (SQLException e) { 

                                           e.printStackTrace(); 

                                   } 

                                   JdbcUtil.release(rs, stmt, conn); 

                           } 

                   } 

           } 

           **********************************************************************************