事務,動態代理,鏈接池

事物:
1開啓事務
2事務滾點
3提交事務
代碼體現:
/*
 create database day19;
 create table account(
  id int primary key ,
  name varchar(100),
  money float
 )character set utf8 collate utf8_general_ci;
 insert into account values(1,'aaa',1000);
 insert into account values(2,'bbb',1000);
 insert into account values(3,'ccc',1000);
 */
public class TransactionDemo1 {
 @Test
 public void testTransaction(){
  Connection conn=null;
  PreparedStatement stmt=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;
   stmt=conn.prepareStatement("update account set money=money+100 where name='ccc'");
   stmt.executeUpdate();
  conn.commit();
  }catch(Exception e){
   e.printStackTrace();
   try {
    if(conn!=null){
    conn.rollback(sp);
    }else{
     conn.rollback();
    }
   } catch (SQLException e1) {
    e1.printStackTrace();
   }
  }finally{
   try {
    conn.commit();
   } catch (SQLException e) {
    e.printStackTrace();
   }
   JdbcUtil.release(null, stmt, conn);
  }
 }
}mysql

模擬鏈接池:
public class SimpleConnectionPool {
 private static LinkedList<Connection> pool=new LinkedList<Connection>();
 static{
  //鏈接池初始化
  try {
   for(int i=0;i<10;i++){
    pool.add(JdbcUtil.getConnection());
   }
  } catch (Exception e) {
   throw new ExceptionInInitializerError("鏈接池初始化失敗");
  }
 }
 public synchronized static Connection getConnection(){
  if(pool.size()>0){
   return pool.removeFirst();
  }else{
   throw new RuntimeException("服務器正忙");
  }
 }
 public static void release(Connection conn){
  pool.addLast(conn);
 面試

事物的隔離級別:
一、事務的特性:(面試題)
原子性:處於同一個事務中的多條語句,要麼全都成功,要麼全都不成成功。
一致性:事務必須使數據庫從一個一致性狀態變換到另一個一致性狀態。好比轉帳:轉帳前a+b=2000,轉帳後a+b=2000
隔離性:多線程併發時,一個事務不能被其餘事務所幹擾。
持久性:數據應該被永久性的保存起來。(硬盤,而不是內存)
ACID
二、事務的隔離性專題
若是不考慮事務的隔離性,會致使如下不正確的問題:
a、髒讀:指一個事務讀到了另一個事務中未提交的數據
b、不可重複讀:指一個事務讀到了另一個事務update後(事務提交了)的數據
c、虛讀:指一個事務讀到了另一個事務insert的數據sql

三、演示操做:
3.1數據庫控制隔離級別相關的語句(必須用在事務之中):數據庫

數據庫有四個隔離級別:
READ UNCOMMITTED:髒讀、不可重複讀、虛讀都有可能發生。
READ COMMITTED:防止髒讀發生;不可重複讀、虛讀都有可能發生。
REPEATABLE READ:(MySQL默認級別)防止髒讀、不可重複讀;虛讀有可能發生。
SERIALIZABLE:防止髒讀、不可重複讀、虛讀的發生安全

特色:從上到下,隔離級別越高,數據越安全,可是效率越低服務器

select @@tx_isolation;  查看當前數據庫的隔離級別
set transaction isolation level 四個級別之一;更改當前事務的隔離級別多線程

代碼體現:
public class TxIsolationDemo {
 @Test
 public void test(){
  Connection conn = null;
  PreparedStatement stmt = null;
  ResultSet rs = null;
  try{
   conn = JdbcUtil.getConnection();
   conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);//只能防止髒讀的發生.注意,必定要放在開始事務以前
   conn.setAutoCommit(false);//開啓事務
   //查詢aaa帳戶的餘額
   stmt = conn.prepareStatement("select * from account where name='aaa'");
   rs = stmt.executeQuery();
   if(rs.next()){
    System.out.println("第一次查詢:"+rs.getString("money"));
   }
   
   //在查詢aaa帳戶的餘額
   stmt = conn.prepareStatement("select * from account where name='aaa'");
   rs = stmt.executeQuery();
   if(rs.next()){
    System.out.println("第二次查詢:"+rs.getString("money"));
   }
   conn.commit();
  }catch(Exception e){
   if(conn!=null){
    try {
     conn.rollback();
    } catch (SQLException e1) {
     e1.printStackTrace();
    }
   }
   e.printStackTrace();
  }finally{
   JdbcUtil.release(rs, stmt, conn);
  }
 }
}併發

基於接口的動態代理:
靜態代理:
代碼體現:
接口:app

public interface Human {
 void sing(float money);
 void dance(float money);
}ide

歌手類:
public class SpringBrother implements Human {
 public void sing(float money){
  System.out.println("開始唱歌"+money);
 }
 public void dance(float money){
  System.out.println("開始跳舞"+money);
 }
}
代理人類:
public class ProxyMan {
 private SpringBrother sb=new SpringBrother();
 public void sing(float money){
  if(money>1000){
   money=money/2;
   sb.sing(money);
  }else{
   throw new RuntimeException("出場費不得低於1000");
  }
 }
 public void dance(float money){
  if(money>1000){
   money=money/2;
   sb.dance(money);
  }else{
   throw new RuntimeException("出場費不得低於1000");
  }
 }
 
}
客戶類:
public class Client {
 private static ProxyMan pm=new ProxyMan();
 public static void main(String[] args) {
  pm.sing(2000);
  pm.dance(2000);
 }
}

動態代理:(在內存中生成代理類或者代理類的實例)
1:基於接口的動態代理
public class Client {
 
 
 public static void main(String[] args) {
  final Human h=new SpringBrother();//原有對象
  Human hMan=(Human)Proxy.newProxyInstance(h.getClass().getClassLoader(), h.getClass().getInterfaces(), new InvocationHandler() {
   //匿名內部類實現接口
   //全部調用被代理類對象的方法,都會通過該方法
   /**
    * Object proxy:代理對象自己的引用
    * Method method:當前調用的是哪一個方法
    * Object[] args:當前調用的方法用到的參數
    */
   public Object invoke(Object proxy, Method method, Object[] args)
     throws Throwable {
    String metnodName=method.getName();
    if("sing".equals(metnodName)){
     float money=(Float) args[0];
     if(money>1000){
      money=money/2;
      h.sing(money);
     }else{
      throw new RuntimeException("出場費不得低於1000");
     }
    }else if("dance".equals(metnodName)){
     float money=(Float) args[0];
     if(money>1000){
      money=money/2;
      h.dance(money);
     }else{
      throw new RuntimeException("出場費不得低於1000");
     }
    }
    return null;
   }
  });
  hMan.sing(10000);
  hMan.dance(10000);
 }
}


2:基於子類的動態代理:
person類:
public class Person {
 public void m1(){
  System.out.println("方法m1執行了");
 }
}
貸代碼體現:

public class PersonDemo {
 public static void main(String[] args) {
  final Person p=new Person();
  Person pp=(Person)Enhancer.create(p.getClass(), new MethodInterceptor(){

   public Object intercept(Object proxy, Method method, Object[] arg2,
     MethodProxy arg3) throws Throwable {
    long time=System.nanoTime();
    Object obj=method.invoke(p, arg2);
    System.out.println(method.getName()+"運行了"+(System.nanoTime()-time));
    return obj;
   }
   
  });
  pp.m1();
 }
}

動態代理實現close方法的改變:
public class MyDataSource3 implements DataSource {
 private static List<Connection> pool = new ArrayList<Connection>();
 static {
  try {
   for (int i = 0; i < 10; i++) {
    Connection conn = JdbcUtil.getConnection();
    pool.add(conn);
   }
  } catch (Exception e) {
   throw new ExceptionInInitializerError(e);
  }
 }

 // 獲取連接
 public synchronized Connection getConnection() throws SQLException {
  if (pool.size() > 0) {
   final Connection conn = pool.remove(0);// com.mysql.jdbc.COnnection
   Connection proxyConn = (Connection) Proxy.newProxyInstance(conn
     .getClass().getClassLoader(), conn.getClass()
     .getInterfaces(), new InvocationHandler() {
    public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
     //若是用戶調用的是close方法,把連接還回池中。其餘方法,用原有對象的
     if("close".equals(method.getName())){
      System.out.println("你調用的是close,還回池中");
      return pool.add(conn);
     }else{
      System.out.println("調用的其餘方法,什麼都沒作");
      return method.invoke(conn, args);
     }
     
    }
   });
   return proxyConn;
  } else {
   throw new RuntimeException("服務器真忙");
  }
 }

 @Override
 public PrintWriter getLogWriter() throws SQLException {
  // TODO Auto-generated method stub
  return null;
 }

 @Override
 public void setLogWriter(PrintWriter out) throws SQLException {
  // TODO Auto-generated method stub

 }

 @Override
 public void setLoginTimeout(int seconds) throws SQLException {
  // TODO Auto-generated method stub

 }

 @Override
 public int getLoginTimeout() throws SQLException {
  // TODO Auto-generated method stub
  return 0;
 }

 @Override
 public <T> T unwrap(Class<T> iface) throws SQLException {
  // TODO Auto-generated method stub
  return null;
 }

 @Override
 public boolean isWrapperFor(Class<?> iface) throws SQLException {
  // TODO Auto-generated method stub
  return false;
 }

 @Override
 public Connection getConnection(String username, String password)
   throws SQLException {
  // TODO Auto-generated method stub
  return null;
 }

}

相關文章
相關標籤/搜索