JDBC事务的隔离级别

一、事务的隔离级别
      多个事务在数据库中同时运行,当他们访问到数据库中的同一个数据的时候,如果没有采用隔离机制,就会导致一些并发问题的发生,在数据库中有以下几个并发问题
            ①读"脏"数据  指事务T1修改了某一数据后,并未提交,而此时事务T2又读到了这个数据(此时T2读到的是T1修改后未提交的数据),然后又因为某种原因导致T1被撤销(即rollback),这时T2读到的数据仍然是T1回滚之前修改的未提交的数据,因此称T2读道德数据为"脏"数据
            ②幻影现象  事务T1按一定的条件读取数据库中的某些数据记录,而事务T2删除了其中的部分内容或又插入了一些记录,当T1再次去读取该数据时,发现某些记录消失了或者多了一些记录,这种现象被称为幻影现象
            ③不可重复读  指的是事务T1读取数据后,事务T2对该数据进行了修改,,使得T1下一次再次读取该数据时与前一次所读到的数据不一致。这就被称之为不可重复读
      为了解决这些问题,数据库中规定了多种事务隔离级别,不同的隔离级别的抗干扰程度不同,隔离级别越高,数据的一致性就越好,但相应的数据库的性能就要差一些,因此应该根据具体的情况来选择隔离级别。在MySQL中有四种隔离级别,分别是以下四种:
            ①读未提交数据  READ UNCOMMITTED 允许事务读取未被其他事务提交的数据,上面三种并发问题都会出现
            ②读已提交数据  READ COMMITED  只允许事务读取已经被其他事务提交的数据,可以避免读"脏数据",但其他两种问题还是会出现
            ③可重复读  REPEATABLE READ  确保一个事务可以多次读取一个相同的数据,在该事务运行期间,其他事务精致访问该数据,可以避免读"脏"数据和不可重复读
            ④串行化  SERIALIZABLE  确保事务可以从一个表中读取相同的行,在这个事务运行期间,禁止其他事务对该表进行修改,所有并发问题都可避免,但数据库的性能比较差
      此外,在MySQL中默认的事务隔离级别为REPEATABLE READ,而Oracle只支持两种事务隔离级别,分别是READ COMMITED与SERIALIZABLE,其默认事务隔离级别为READ COMMITED
      所以,我们在利用JDBC对数据库执行操作的时候,想要避免并发问题,可以在建立了数据库连接利用Conneciton对象中的setTransactionIsolation()方法设置隔离级别,该方法的参数为一个常量,分别是TRANSACTION_READ_UNCOMMITTED、TRANSACTION_READ_COMMITTED、TRANSACTION_REPEATABLE_READ和TRANSACTION_SERIALIZABLE他们分别对应前面说的隔离级别。
下面是一个具体的事例来测试事务的隔离级别:
现在本地数据库中有这样一个表:
下面进行测试
//测试类 用来测试事务的隔离级别的类
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.Test;
public class TestTransaction {//事务的多个操作
       DAO dao = new DAO();
       @Test
       public void testTransactionIsolation(){//事务一  执行更新操作
             Connection con = null;
             try {
                    con = JDBCTools.getConnection();
                    con.setAutoCommit(false);
                    String sql = "UPDATE customer SET money=money-500 WHERE id=1";
                    dao.update(con, sql);
                    con.commit();//在测试时在此处加个断点,debug时停在此处,然后去运行事务二,即可看到结果
             } catch (Exception e) {
            e.printStackTrace();
             }finally{
                    dao.release(null, con, null);
             }
       }
       @Test
       public void testTransactionIsolation1(){//事务二  查询操作
             Connection con = null;
             try {
                    con = JDBCTools.getConnection();
                    String sql = "SELECT money FROM customer WHERE id=1";
                    Integer value = getvalues(con, sql);
                    System.out.println(value);
             } catch (Exception e) {
            e.printStackTrace();
             }finally{
                    dao.release(null, con, null);
             }
       }
    /**
     * 返回某条记录的某一字段的值
     * @param sql
     * @param args
     * @return
     */
    public <E> E getvalues(Connection con,String sql,Object ... args){
       PreparedStatement ps = null;
       ResultSet rs = null;//所得结果集只为一行一列
       try {
                    con.setTransactionIsolation(con.TRANSACTION_READ_COMMITTED);//设置隔离级别为读已提交的
                    ps = con.prepareStatement(sql);
                    for(int i = 0;i < args.length;i++){
                           ps.setObject(i+1,args[i]);
                    }
                    rs = ps.executeQuery();
                    if(rs.next()){
                           return (E)rs.getObject(1);
                    }
             } catch (Exception e) {
            e.printStackTrace();
             }finally{
                    JDBCTools.release(rs, null, ps);
             }
       return null;
    }
}
//DAO类  包含了对数据库执行一系列操作的方法
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.beanutils.BeanUtils;
public class DAO {
       /**
        * 数据库的更新
        * @param sql
        * @param args
        */
    public void update(Connection con,String sql,Object ... args){//数据库的更新操作,可实现增、删、改的操作
       PreparedStatement ps = null;
       
       try {
                    ps = con.prepareStatement(sql);
                    for(int i = 0;i<args.length;i++){//填充占位符
                           ps.setObject(i + 1, args[i]);
                    }
                    ps.executeUpdate();
             } catch (Exception e) {
                    e.printStackTrace();
             }finally{
                    JDBCTools.release(null, null, ps);
             }
    }
    /**
     * 返回某条记录的某一字段的值
     * @param sql
     * @param args
     * @return
     */
    public <E> E getvalues(Connection con,String sql,Object ... args){
       PreparedStatement ps = null;
       ResultSet rs = null;//所得结果集只为一行一列
       try {
                    ps = con.prepareStatement(sql);
                    for(int i = 0;i < args.length;i++){
                           ps.setObject(i+1,args[i]);
                    }
                    rs = ps.executeQuery();
                    if(rs.next()){
                           return (E)rs.getObject(1);
                    }
             } catch (Exception e) {
            e.printStackTrace();
             }finally{
                    JDBCTools.release(rs, null, ps);
             }
       return null;
    }
    /**
     * 数据库的单个查询操作
     * @param clazz
     * @param sql
     * @param args
     * @return
     */
    public <T> T getForOne(Connection con,Class<T> clazz,String sql,Object ... args){//数据库的查询操作
       T entity = null;
       PreparedStatement ps = null;
       ResultSet rs = null;
       
       try {
                    ps = con.prepareStatement(sql);
                    for(int i = 0;i < args.length;i++){//填充占位符
                           ps.setObject(i + 1,args[i]);
                    }
                    rs = ps.executeQuery();//得到结果集,利用它可以知道某一行中某一列的具体值
                    if(rs.next()){
                           ResultSetMetaData rsmd = rs.getMetaData();//该对象可以知道结果集有几列,以及每一列所对应的别名等信息
                           Map<String,Object> valueMap = new HashMap<>();//建立Map集合用来存结果集中的列名以及对应的属性值
                           for(int i = 0;i < rsmd.getColumnCount();i++){
                                 String ColumnLabel = rsmd.getColumnLabel(i + 1);//得到查询出的每一列的列名
                                 Object ColumnValue = rs.getObject(i + 1);//得到每一列所对应的值
                                 valueMap.put(ColumnLabel, ColumnValue);
                           }
                if(valueMap.size() > 0){
                    entity = clazz.newInstance();
                           for(Map.Entry<String, Object> entry : valueMap.entrySet()){//利用反射为对应的属性赋值
                               String fieldName = entry.getKey();
                               Object fieldvalue = entry.getValue();
//                             Field f1 = clazz.getDeclaredField(fieldName);
//                             f1.setAccessible(true);
//                             f1.set(entity, fieldvalue);
                               BeanUtils.setProperty(entity, fieldName, fieldvalue);//对Java类属性赋值
                           }
                }
                    }
             } catch (Exception e) {
            e.printStackTrace();
             }finally{
                    JDBCTools.release(rs, null, ps);
             }
       
       return entity;
    }
    /**
     * 数据库的多个查询返回结果集合的操作
     * @param clazz
     * @param sql
     * @param args
     * @return
     */
    public <T> List<T> getForList(Connection con,Class<T> clazz,String sql,Object ... args){
       List<T> list =  new ArrayList<>();
       PreparedStatement ps = null;
       ResultSet rs = null;
       try {
                    ps = con.prepareStatement(sql);
                    for(int i = 0;i < args.length;i++){
                           ps.setObject(i + 1, args[i]);
                    }
                    rs = ps.executeQuery();//得到结果集
                    List<Map<String,Object>> valueList = new ArrayList<>();//用于存放多条记录的List集合
                    ResultSetMetaData rsmd = rs.getMetaData();
                    Map<String,Object> map = null;//存放一条记录的Map集合
                    while(rs.next()){//处理结果集
                           map = new HashMap<String,Object>();
                           for(int i = 0;i < rsmd.getColumnCount();i++){
                                 String columLabel = rsmd.getColumnLabel(i + 1);
                                 Object value = rs.getObject(i + 1);
                                 //将一条记录存入mao集合中
                                 map.put(columLabel, value);
                           }
                           valueList.add(map);
                    }
                    //判断valueList是否为空  若不为空,则遍历valueList集合,得到一个个Map对象,将其转为Class参数对应的对象
                    T bean = null;
                    if(valueList.size() > 0){
                           for(Map<String,Object> each : valueList){
                                 for(Map.Entry<String, Object> e : each.entrySet()){
                                        String fieldname = e.getKey();
                                        Object fieldvalue = e.getValue();
                                        //为对应的Java类属性赋值
                                        bean =  clazz.newInstance();
                                        BeanUtils.setProperty(bean, fieldname, fieldvalue);
                                 }
                                 //将T对象放入list中
                                 list.add(bean);
                           }
                    }
             } catch (Exception e) {
            e.printStackTrace();
             }finally{
                    JDBCTools.release(rs, null, ps);
             }
       return list;
    }
}
//JDBC工具类  包含数据库的连接,更新,关闭等功能
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
//JDBC的工具类,用于关闭数据库连接操作,更新操作和查询操作
public class JDBCTools {
       public static Connection getConnection() throws Exception{//连接数据库
             String driverClass = null;
             String url = null;
             String user = null;
             String password = null;
             
             Properties properties = new Properties();
             
             InputStream in = Review.class.getClassLoader().getResourceAsStream("jdbc.properties");
             properties.load(in);
             
             driverClass = properties.getProperty("driver");
             url = properties.getProperty("jdbcurl");
             user = properties.getProperty("user");
             password = properties.getProperty("password");
             Class.forName(driverClass);
             return DriverManager.getConnection(url, user, password);
       }
       public static void release(Connection con , Statement state){//关闭数据库连接
             if(state != null){
                    try {
                           state.close();
                    } catch (SQLException e) {
                           e.printStackTrace();
                    }
             }
             if(con != null){
                    try {
                           con.close();
                    } catch (SQLException e) {
                           e.printStackTrace();
                    }
             }
             
       }
       public static void release(ResultSet rs , Connection con , Statement state){//关闭数据库连接
             if(rs != null)
             {
                    try {
                           rs.close();
                    } catch (SQLException e) {
                           e.printStackTrace();
                    }
             }
             if(state != null){
                    try {
                           state.close();
                    } catch (SQLException e) {
                           e.printStackTrace();
                    }
             }
             if(con != null){
                    try {
                           con.close();
                    } catch (SQLException e) {
                           e.printStackTrace();
                    }
             }
       }
}
最后的运行结果为
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值