JDBC高级篇

一、JDBC优化以及工具类的封装

1.1现有问题:

我们在使用JDBC的过程中,发现部分代码存在冗余的问题:创建连接池;获取连接;连接的回收。

1.2.JDBC工具类封装V1.0

(1)维护一个连接池对象;

(2)对外提供在连接池中获取连接的方法;

(3)对外提供回收连接的方法;

注意:工具类仅对外提供共性的功能代码,所以方法均为静态方法;

resources/db.properties配置文件:

# druid连接池需要的配置参数,key固定命名。
driverClassName=com.mysql.cj.jdbc.Driver
username=root
password=atguigu
url=jdbc:mysql:///atguigu
public class JDBCUtil {
    //创建连接池引用,因为要提供给当前项目的全局使用,所以创建为静态的
    private static DataSource dataSource;
    //在项目启动时,即创建连接池对象,赋值给dataSource
    static {
        try {
            Properties properties = new Properties();
            InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
            properties.load(inputStream);
            dataSource = DruidDataSourceFactory.createDataSource(properties);
         }catch(Exception e){
            throw new RuntimeException(e);
         }
    }
    public static Connection getconnection(){
        try {
            return dataSource.getConnection();
        }   catch(SQLException e){    
            throw new RuntimeException(e);
        }
    }
    public static void release(Connection connection){
        try {
            connection.close();
        } catch (SQLException e){
            throw new RuntimeException(e);
        }
    }
}

1.3.ThreadLocal

JDK1.2的版本中就提供java.lang.ThreadLocal,为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。通常用来在在多线程中管理共享数据库连接、Session等。

ThreadLocal用于保存某个线程共享变量,原因是在Java中每一个线程对象中都有一个ThreadLocalMap<ThreadLocal,Object>,其key就是一个ThreadLocal而Object即为该线程的共享变量。而这个map是通过ThreadLocal的set和get方法操作的。对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。

ThreadLocal对象.get:获取ThreadLocal中当前线程共享变量的值;

ThreadLocal对象.set:设置ThreadLocal中当前线程共享变量的值;

ThreadLocal对象.remove:移除ThreadLocal中当前线程共享变量的值;

1.4.JDBC工具类封装V2.0

(1)维护一个连接池对象,同时维护了一个线程绑定变量的ThreadLocal对象;

(2)对外提供在连接池中获取连接的方法;

(3)对外提供回收连接的方法;

public class JDBCUtil {
    //创建连接池引用,因为要提供给当前项目的全局使用,所以创建为静态的
    private static DataSource dataSource;
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    //在项目启动时,即创建连接池对象,赋值给dataSource
    static {
        try {
            Properties properties = new Properties();
            InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("db.properties");
            properties.load(inputStream);
            dataSource = DruidDataSourceFactory.createDataSource(properties);
         }catch(Exception e){
            throw new RuntimeException(e);
         }
    }
    public static Connection getConnection(){
        try {
            //在ThreadLocal中获取Connection
            Connection connection = threadLocal.get();
            //threadLocal里没有存储Connection,也就是第一次获取
            if(connection == null){
                //在连接池中获取一个连接,存储在threadLocal里
                connection = dataSource.getConnection();
                threadLocal.set(connection);
            }
            return connection;
        }   catch(SQLException e){    
            throw new RuntimeException(e);
        }
    }
    public static void release(connection connection){
        try {
            Connection connection = threadLocal.get();
            if(connection!=null){
                //从threadLocal中移除当前已经存储的Connection对象        
                threadLocal.remove();
                //将Connection对象归还给连接池
                connection.close();
            }
        }catch(SQLException e){
            throw new RuntimeException(e);
        }
    }
}

二、DAO封装以及BaseDAO工具类

2.1.DAO概念:

DAO:Data Access Object,数据访问对象。Java是面向对象语言,数据在Java中通常以对象的形式存在。一张表对应一个实体类,一张表的操作对应一个DAO对象。在Java操作数据库时,我们会将对同一张表的增删改査操作统一维护起来,维护的这个类就是DAO层。DAO层只关注对数据库的操作,供业务层Service调用,将职责划分清楚。

2.2.BaseDAO的概念:

基本上每一个数据表都应该有一个对应的DAO接口及其实现类,发现对所有表的操作(增、删、改、查)代码重复度很高,所以可以抽取公共代码,给这些DAO的实现类可以抽取一个公共的父类,复用增删改查的基本操作,我们称为BaseDAO。

//新建一个DAO包,在该包中新增一个名为EmployeeDAO的接口
public interface EmployeeDAO {
    List<Employee> selectAll();
    Employee selectByEmpId(Integer empId);
    int insert(Employee employee);
    int update(Employee employee);
    int delete(Integer empId);
}
//在该DAO包中新建一个impl子包,其中新增EmployeeDAO接口的实现类,实现具体的增删改查的操作
public class BaseDAO{
    public int executeUpdate(String sql,Object... params){
        Connection connection = JDBCUtilV2.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        if(params!=null && params.length>0){
            for(int i=0;i<params.length;i++){
                //占位符是从1开始的,参数的数组是从0开始的
                preparedStatement.setObject(i+1,params[i]);
            }
        }
        int row = preparedStatement.executeUpdate();
        preparedStatement.close();
        JDBCUtilV2.release();
        return row;
    }
    public <T> List<T> executeQuery(class<T> clazz,String sql,Object... params) throws Exception{
        Connection connection = JDBCUtilV2.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        if(params!=null && params.length>0){
            for (int i=0;i<params.length;i++){
                preparedStatement.setObject(i+1, params[i]);
            }
        }
        ResultSet resultSet = preparedStatement.executeQuery();
        ResultSetMetaData metaData = resultSet.getMetaData();
        List<T> list = new ArrayList<>();
        while(resultSet.next()){
            T t = clazz.newInstance();
            for(int i=1;i <= columnCount;i++){
                Object value = resultSet.getObject(i);
                String fieldName = metaData.getColumnLabel(i);
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                field.set(t,value);
            }
            list.add(t);
        }
        resultSet.close();
        preparedStatement.close();
        JDBCUtilV2.release();
        return list;
    }
}
//在该DAO包中新建一个impl子包,其中继承BaseDAO类,在实现EmployDAO中的方法实现具体的增删改查的操作

三、事务

3.1.事务回顾:

数据库事务就是一种SQL语句执行的缓存机制,不会单条执行完毕就更新数据库数据,最终根据缓存内的多条语句执行结果统一判定。一个事务内所有语句都成功及事务成功,我们可以触发commit提交事务来结束事务,更新数据。一个事务内任意一条语句失败,即为事务失败,我们可以触发rollback回滚结束事务,数据回到事务之前状态。

3.2.事务的特性:

(1)原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

(2)一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态;

(3)隔离性(lsolation):事务的隔离性是指一个事务的执行不能被其他事务干扰, 即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

(4)持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的, 接下来的其他操作和数据库故障不应该对其有任何影响;

3.3事务的提交方式:

(1)自动提交:每条语句自动存储一个事务中,执行成功自动提交,执行失败自动回滚;

(2)手动提交:手动开启事务,添加语句,手动提交或者手动回滚即可

3.4.JDBC中实现事务

try{
    connection.setAutoCommit(false);//关闭自动提交
    //注意:只要当前connection对象进行数据库操作,都不会自动提交事务
    //prepareStatement-单的数据库动作crud
    //所有操作执行正确,提交事务
    connection.commit();
}catch(Execption e){
    //出现异常,则回滚事务!
    connection.rollback();
}

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值