Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)

Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)

JDBC对事物的处理

数据准备:

CREATE TABLE account(
       id number(10),
       name varchar2(20),
       balance number(10,2)
)
--插入数据
insert into account values(1,'jack',1000.00);
insert into account values(2,'rose',1000.00);
--查询
SELECT * FROM account;

主要API
与Connection相关的方法:
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)
操作步骤:

  1. 获取连接
  2. 开启事务
  3. 获取PreparedStatement对象
  4. 执行sql
  5. 正常情况下 提交事务
  6. 出现异常 回滚事务
  7. 释放资源
// 使用事务  完成转账操作
@Test
public  void  testTx() {
    //1 获取连接
    Connection  conn = JDBCUtils.getConnection();
    PreparedStatement ps = null;
    try {
        // 开启事务 将事务的提交设置为手动模式
        conn.setAutoCommit(false);
        // 2 获取PreparedStatement
        String sql1 = "update account  set  balance = balance - ? where id=?";
        ps = conn.prepareStatement(sql1);
        //3 绑定参数
        ps.setDouble(1,200);
        ps.setInt(2,1);
        ps.executeUpdate();
        // 出现异常
        System.out.println(1/0);
        String sql2 = "update account  set  balance = balance + ? where id=?";
        ps = conn.prepareStatement(sql2);
        ps.setDouble(1,200);
        ps.setInt(2,2);
        ps.executeUpdate();
        //提交事务
        conn.commit();
        System.out.println("转账成功");
    } catch (Exception e) {
        e.printStackTrace();
        try {
            //回滚事务
            conn.rollback();

        } catch (SQLException se){
           se.printStackTrace();
        }
        System.out.println("转账失败");
    }finally {
        JDBCUtils.close(ps,conn);
    }

数据库连接池技术

解决传统开发中数据库频繁连接释放的问题。

数据库连接池的思想:

就是为数据库建立一个“缓冲池”,预先在缓冲池中放入一定数量的连接,当需要建立数据库连接的时候,从缓冲池汇总并取出一个来使用,当使用完毕之后,再将连接归还到缓冲池。

数据库连接池的作用:负责数据库连接的分配、管理、释放等工作。他允许程序重复使用一个现有的连接,而不是重新建立一个。

数据库连接池在初始化的时候就创建一定数量的连接放到连接池中,这些连接是由连接池的最小连接数来决定,无论连接是否被使用,连接都将保证在连接池中存在这最小数量的连接。当连接不满足需求的时候,他会再次创建一定数量的连接,创建的连接的上限将由最大连接数来决定。当程序的请求的连接数超过了连接池所能提供的最大连接数的时候,此时这些请求将被加入到排队队列中等待空闲连接。

数据库连接池优点:

  1. 资源的重用。
  2. 更快的系统响应。
  3. 新的资源分配手段
  4. 统一的连接管理,避免了数据库连接的泄露。

常见的数据库连接池:

JDBC连接池使用的是javax.sql , Interface DataSource 。
接口的常见实现:

  • DBCP 是Apache提供的数据库连接池。
  • C3P0 是一个开源组织提供的一个数据库连接池。速度相对DBCP要慢一些。Hibernate的默认使用技术。
  • Druid 是由阿里提供的一个数据库连接池,集DBCP和C3P0的优点与一身

DataSource通常被称为数据源。他包含了数据库连接池的创建和管理两部分工作。
使用中,我们将使用DataSource来取代DriverManager获取数据库连接Connection 从而提高数据库的访问速度
当使用数据库连接池获取到的连接在调用Connection的close方法的时候 ,不在是直接将连接关闭,而是将连接归还到连接池。

连接池的使用:

C3P0的使用步骤:

  1. 导包:
    Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)
  2. 配置连接池
  3. 创建数据源对象
  4. 获取连接
//使用C3P0数据库连接池获取连接
@Test
public  void getConnectionByC3p0() throws PropertyVetoException, SQLException {
    // 获取数据源
    ComboPooledDataSource ds = new ComboPooledDataSource();
    // 设置连接属性
    ds.setDriverClass("oracle.jdbc.driver.OracleDriver");
    ds.setJdbcUrl("jdbc:oracle:thin:@192.168.25.129:1521:orcl");
    ds.setUser("scott");
    ds.setPassword("tiger");
    // 获取连接
    for(int i = 0 ; i < 5;i++){
        Connection conn = ds.getConnection();
        System.out.println(conn);
    }
}

使用C3P0的配置文件来获取连接

//使用C3P0的配置文件来配置数据库连接池
@Test
public void getConnection2() throws SQLException {
    ComboPooledDataSource ds = new ComboPooledDataSource();
    for(int i = 0 ; i < 5;i++){
        Connection conn = ds.getConnection();
        System.out.println(conn);
    }
}

配置文件 默认的文件名c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <!--        超时时间 毫秒-->
        <property name="checkoutTimeout">30000</property>
        <!--        初始化连接数-->
        <property name="initialPoolSize">10</property>
        <!--        最大空闲数-->
        <property name="maxIdleTime">30</property>
        <!--        最大连接数-->
        <property name="maxPoolSize">100</property>
        <!--        最小连接数-->
        <property name="minPoolSize">10</property>
        <!--        每个连接随支持 最大的statement对象-->
        <property name="maxStatements">200</property>
        <!--        当链接数不足时,每次向数据库申请的连接数-->
        <property name="acquireIncrement">5</property>
        <!--链接属性的配置  链接属性的name值是固定的  必须参考官方文档来写-->
        <property name="driverClass">oracle.jdbc.driver.OracleDriver</property>
        <property name="jdbcUrl">jdbc:oracle:thin:@192.168.25.129:1521:orcl</property>
        <property name="user">scott</property>
        <property name="password">tiger</property>
    </default-config>
</c3p0-config>

DBCP:

导包
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)

@Test
public void getConnectionByDBCP() throws SQLException {
    //创建 数据源
    BasicDataSource ds = new BasicDataSource();
    // 设置连接属性
    ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
    ds.setUrl("jdbc:oracle:thin:@192.168.25.129:1521:orcl");
    ds.setUsername("scott");
    ds.setPassword("tiger");
    // 配置连接池
    ds.setInitialSize(5);
    for(int i = 0 ; i < 5;i++){
        Connection conn = ds.getConnection();
        System.out.println(conn);
    }
}

使用配置文件

http://commons.apache.org/proper/commons-dbcp/configuration.html

@Test
public void getConnectionByDBCP2() throws Exception {
    Properties ps = new Properties();
    ps.load(DataSourceDemo.class.getClassLoader().getResourceAsStream("dbcp.properties"));
    BasicDataSource bds = BasicDataSourceFactory.createDataSource(ps);
    for(int i = 0 ; i < 5;i++){
        Connection conn = bds.getConnection();
        System.out.println(conn);
    }
}

配置文件 dbcp.properties

driverClassName= oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.25.129:1521:orcl
username=scott
password=tiger
initialSize=10
maxTotal=20
maxIdle=10
minIdle=5

Druid:

国内开发者最受欢迎的数据库连接池
导包:
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)

@Test
public void getConnectionByDruid() throws Exception {
     Properties ps = new Properties();
     ps.load(DataSourceDemo.class.getClassLoader().getResourceAsStream("druid.properties"));
     DataSource ds = DruidDataSourceFactory.createDataSource(ps);
     for(int i = 0 ; i < 5;i++){
         Connection conn = ds.getConnection();
         System.out.println(conn);
     }
}

配置文件 druid.properties

url=jdbc:oracle:thin:@192.168.25.129:1521:orcl
driverClassName=oracle.jdbc.driver.OracleDriver
username=scott
password=tiger
initialSize=10
maxActive=20
maxWait=1000

Jdbc工具类的重构:

public class JDBCUtils2 {
    // 数据源
    private static DataSource ds;
    // 初始化数据源  使用druid数据源
    static{
        try {
            Properties ps = new Properties();
            ps.load(JDBCUtils2.class.getClassLoader().getResourceAsStream("druid.properties"));
            ds= DruidDataSourceFactory.createDataSource(ps);
        }  catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //获取连接
    public static Connection getConnection(){
        Connection conn = null;
        try {
           conn =  ds.getConnection();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return conn;
    }
    //释放资源
    public  static void close(ResultSet resultSet , Statement stmt , Connection conn){
        if(resultSet !=null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();// 归还连接
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
    //释放资源
    public  static void close( Statement stmt , Connection conn){
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
    // 获取数据源的方法
    public  static DataSource getDataSource(){
        return  ds;
    }
}

测试:

@Test
public void jdbcUtilsTest(){
    for(int i = 0 ; i < 5;i++){
        Connection conn = JDBCUtils2.getConnection();
        System.out.println(conn);
    }
}

JDBC工具类库—Apache Common-DBUtils

特点:

  • Small - you should be able to understand the whole package in a short amount of time.
  • Transparent - DbUtils doesn’t do any magic behind the scenes. You give it a query, it executes it and cleans up for you.
  • Fast - You don’t need to create a million temporary objects to work with DbUtils.

DBUtils是一个开源JDBC工具类库。对JDBC的操作进行了封装。简化了JDBC编码。

常见API:

QueryRunner 负责执行查询或者更新
ResultSetHandler 负责结果集的处理
DbUtils 操作的工具类

DbUtils:

提供了关闭数据库连接、装载驱动等工作。
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)

QueryRunner:

封装了SQL查询、更新等相关的数据库操作,简化了操作的步骤,提供ResultSetHanddler 来处理结果集。
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)

ResultSetHanddler:

实现类
Oracle_Day06(JDBC对事物的处理,JDBC工具类库—Apache Common-DBUtils,项目中数据访问层的处理)

DBUtils的使用:

public class DBUtisDemo {
    // 测试插入数据
    @Test
    public  void insertTest() throws SQLException {
        // 创建QueryRunner对象
        QueryRunner qr = new QueryRunner();
        String sql = "insert into student(id,name,gender,birthday) values(?,?,?,?)";
        Connection conn = JDBCUtils2.getConnection();
        int row = qr.update(conn,sql,6,"太白金星",1,java.sql.Date.valueOf("2021-01-01"));
        System.out.println("插入了"+row+"条记录");
        DbUtils.close(conn);
    }
    //测试更新
    @Test
    public  void updateTest() throws SQLException {
        // 创建QueryRunner对象
        QueryRunner qr = new QueryRunner();
        String sql = "update student set name=? where id=?";
        Connection conn = JDBCUtils2.getConnection();
        int row = qr.update(conn,sql,"太上老君",6);
        System.out.println("更新了"+row+"条记录");
        DbUtils.close(conn);
    }

    @Test
    public  void deleteTest() throws SQLException {
        // 创建QueryRunner对象
        QueryRunner qr = new QueryRunner();
        String sql = "delete from student where id=?";
        Connection conn = JDBCUtils2.getConnection();
        int row = qr.update(conn,sql,6);
        System.out.println("删除了"+row+"条记录");
        DbUtils.close(conn);
    }
}

DBUtils执行查询:

// 查询一个对象
@Test
public  void selectObjTest() throws SQLException {
    // 获取数据源
    DataSource ds = JDBCUtils2.getDataSource();
    // 利用数据源构建QueryRunner对象
    QueryRunner qr = new QueryRunner(ds);
    String sql = "Select * from student where id = ?";
    // BeanHandler 来处理结果集  可以直接得到我们想要的对象  要求使用时列名需要和javabean的 属性名一致
    Student stu =  qr.query(sql,new BeanHandler<>(Student.class),1);
    System.out.println(stu);
}
// 查询一个对象 列名和属性名不一致  可以使用查询的时候的字段的别名来映射我们的javabean的属性
@Test
public  void selectObjTest2() throws SQLException {
    // 获取数据源
    DataSource ds = JDBCUtils2.getDataSource();
    // 利用数据源构建QueryRunner对象
    QueryRunner qr = new QueryRunner(ds);
    String sql = "Select  id, name stuName,gender,birthday from student where id = ?";
    // BeanHandler 来处理结果集  可以直接得到我们想要的对象  要求使用时列名需要和javabean的 属性名一致
    Student stu =  qr.query(sql,new BeanHandler<>(Student.class),1);
    System.out.println(stu);
}
// 查询多条记录 将查询到的结果封装成一个集合
@Test
public void  selelctListTest() throws SQLException {
    // 获取数据源
    DataSource ds = JDBCUtils2.getDataSource();
    // 利用数据源构建QueryRunner对象
    QueryRunner qr = new QueryRunner(ds);
    String sql = "Select  id, name stuName,gender,birthday from student ";
    // BeanHandler 来处理结果集  可以直接得到我们想要的对象  要求使用时列名需要和javabean的 属性名一致
    List<Student> stuList =  qr.query(sql,new BeanListHandler<>(Student.class));
    System.out.println(stuList);
}
// 自定义结果集处理器
@Test
public void  selelctListTest2() throws SQLException {
    // 获取数据源
    DataSource ds = JDBCUtils2.getDataSource();
    // 利用数据源构建QueryRunner对象
    QueryRunner qr = new QueryRunner(ds);
    String sql = "Select  id, name,gender,birthday from student ";
    // BeanHandler 来处理结果集  可以直接得到我们想要的对象  要求使用时列名需要和javabean的 属性名一致
    List<Student> stuList =  qr.query(sql, new ResultSetHandler<List<Student>>() {
        @Override
        public List<Student> handle(ResultSet resultSet) throws SQLException {
            List<Student> studentList = new ArrayList<>();
           while(resultSet.next()){
               int id = resultSet.getInt("id");
               String name = resultSet.getString("name");
               int gender = resultSet.getInt("gender");
               Date biretday = resultSet.getDate("birthday");
               Student student =  new Student(id,name,gender,biretday);
               studentList.add(student);
           }
           return studentList;
        }
    });
    System.out.println(stuList);
}
// 查询单个值 记录数  最大值 最小值  平均值 和
@Test
public void selectValueTest() throws SQLException {
    DataSource ds = JDBCUtils2.getDataSource();
    QueryRunner qr = new QueryRunner(ds);
    String countSql = "select count(id) from student";
    BigDecimal count =   qr.query(countSql,new ScalarHandler<BigDecimal>());
    System.out.println(count.intValue());
    // 获取年龄最小的
    String ageSql = "select max(birthday) from student";
    Date birthday =  qr.query(ageSql,new ScalarHandler<Date>());
    System.out.println(birthday);
}

事务的处理:

// 事务处理
@Test
public void txTest(){
    Connection conn = JDBCUtils2.getConnection();
    QueryRunner qr = new QueryRunner();
    try {
        conn.setAutoCommit(false);
        String sql1 = "update account set balance=balance - ? where id=?";
        qr.update(conn,sql1,100,1);
        System.out.println(1/0);
        String sql2 = "update account set balance=balance + ? where id=?";
        qr.update(conn,sql2,100,2);
        conn.commit();
        System.out.println("转账成功");
    } catch ( Exception throwables) {
        throwables.printStackTrace();
        try {
            DbUtils.rollbackAndClose(conn);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        System.out.println("转账失败");
    }finally {
        try {
            DbUtils.close(conn);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}

项目中数据访问层的处理

一般都将数据访问层定义为DAO data access Object 将包括对数据的CRUD操作
Dao接口:

public interface IStudentDao {
    void insert(Student stduent);
    void update(Student stduent);
    void delete(int id);
    Student select(int id);
    List<Student> selectAll();
    List<Student> pageList(int currentPage, int pages);
}

BaseDao:

public class BaseDao {
    // 对增删改的封装
    public int update(String sql,Object...objs){
        DataSource ds = JDBCUtils2.getDataSource();
        QueryRunner qr = new QueryRunner(ds);
        int row = 0 ;
        try {
            row = qr.update(sql,objs);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  row;
    }
    // 查询一个对象
    public <T> T getObject(String sql,Class<? extends T> clazz ,Object ... objs){
        DataSource ds = JDBCUtils2.getDataSource();
        QueryRunner qr = new QueryRunner(ds);
        T t = null;
        try {
            t =  qr.query(sql,new BeanHandler<>(clazz),objs);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  t;
    }
    // 查询结果为一个集合  支持分页查询
    public <T> List<T> getObjectList(String sql ,Class<? extends  T> clazz,Object... objs){
        DataSource ds = JDBCUtils2.getDataSource();
        QueryRunner qr = new QueryRunner(ds);
        List<T>  list = new ArrayList<>();
        try {
            list =  qr.query(sql,new BeanListHandler<T>(clazz),objs);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  list;
    }
}

Dao实现:

public class StudentDaoImpl extends BaseDao implements IStudentDao {
    @Override
    public void insert(Student stduent) {
        String sql = "insert into";
            update(sql,stduent);
    }

    @Override
    public void update(Student stduent) {
        String sql= "";
        update(sql,stduent);
    }

    @Override
    public void delete(int id) {
        String sql ="";
        update(sql ,id);
    }

    @Override
    public Student select(int id) {
        String sql= "";
        return getObject(sql,Student.class,id);
    }

    @Override
    public List<Student> selectAll() {
        String sql ="";
        return getObjectList(sql,Student.class) ;
    }

    @Override
    /*
      (currentPage -1 ) * pages   0   5
       (currentPage  * pages 5   10
     */
    public List<Student> pageList(int currentPage, int pages) {
        String sql = "select * from (select rownum  r, student.* from student ) temp where temp.r >? and temp.r <= ?";
        List<Student> stuList = getObjectList(sql,Student.class,(currentPage -1 ) * pages,currentPage * pages);
        return stuList;
    }
}

测试:

public class DaoTest {
    @Test
    public void pageListTest(){
        IStudentDao dao = new StudentDaoImpl();
       List<Student> list = dao.pageList(2,3);
        System.out.println(list);
    }
}
上一篇:day06


下一篇:Day06 索引及执行计划