数据库MySQL2 存储过程 事务

来源:互联网 发布:邓肯马龙交手数据 编辑:程序博客网 时间:2024/05/18 03:12
一、获取数据库自动生成的主键
            主键的值最好由自己的程序来维护
            注: 只对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);
                          }
                  }
          }
          **********************************************************************************
0 0
原创粉丝点击