Java数据库的连接—JDBC(二)

四.数据库连接池技术

4.1 连接池技术的简介

        在与数据库连接过程中,会非常消耗内存,性能大打折扣。如果每次请求都去重新连接数据库。那么,宕机的几率很高。因此,我们可以使用连接池技术。

        连接池的工作原理:

        连接池对象在初始化阶段 一次性创建N个连接对象,这些连接对象存储在连接池对象中。当有请求过来时,先从连接池中寻找空闲连接对象并使用,当使用完后,将连接对象归还给连接池,而不是真正意义上断开连接。这样也可以满足成千上万个请求,同时并提高了数据库的性能。

        常用的连接池技术:

- dbcp   :是apache组织旗下的一个数据库连接池技术产品
- c3p0   :是一个开源的连接池技术
- druid   :是阿里的数据库连接池技术(最常用)

4.2 dbcp 

4.2.1资源jar包:

commons-dbcp2-2.6.0.jar
commons-pool2-2.4.3.jar
commons-logging.jar

4.2.2 配置文件dbcp.properties

此配置文件请放在src目录下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/bd1906
username=root
pwd=123456
maxTotal=50
maxIdle=10
minIdle=3
initialSize=5
maxWaitMillis=60000

4.3 c3p0

4.3.1 资源jar包

c3p0-0.9.5-pre8.jar
mchange-commons-java-0.2.7.jar

4.3.2 配置文件c3p0-config.xml

配置文件请放在src目录下

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
   <default-config>
       <property name="user">root</property>
       <property name="password">123456</property>
       <property name="jdbcUrl">jdbc:mysql://localhost:3306/bd1901</property>
       <property name="driverClass">com.mysql.jdbc.Driver</property>
       <property name="acquireIncrement">10</property>
       <property name="maxPoolSize">50</property>
       <property name="minPoolSize">2</property>
       <property name="initialPoolSize">5</property>
       <property name="maxIdleTime">600</property>
   </default-config>
</c3p0-config>

4.3.3 DBUtilc3p0类型的编写

import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DBUtilC3p0 {
   //构造器会自动检索src下有没有指定文件名称的配置文件,然后会自动赋值给其相应的属性
   private static ComboPooledDataSource pool = new ComboPooledDataSource("c3p0-config");

   public static Connection getConnection() throws SQLException {
       //从连接池中获取空闲对象
       return pool.getConnection();
   }
   public static void closeConnection(Connection conn, Statement stat, ResultSet rs){
       try {
           if(rs!=null){
               rs.close();
           }
           if(stat!=null){
               stat.close();
           }
           if(conn !=null){
               conn.close();   //会将连接对象归还给连接池内
           }
       } catch (SQLException e) {
           e.printStackTrace();
       }
   }
   public static void main(String[] args) throws SQLException {
       Connection conn = getConnection();
       System.out.println(conn);
       conn.close();
   }
}

4.4 druid 

4.4.1 资源jar包

druid-1.1.18.jar

4.4.2 配置文件druid.properties

放在src目录下。注意,前面的key值是固定写法

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/bd1901
username=root
password=123456
maxActive=20
minIdle=3
initialSize=5
maxWait=60000

5.4.3 DBUtildruid类型的编写

import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSourceFactory;
public class DBUtil_druid {
   //创建连接池对象
   private static DataSource pool = null;
   static {
       try {
           //使用类加载器提供的方法读取db.properties,返回一个字节流对象
           InputStream is = DBUtil_druid.class.getClassLoader().
               getResourceAsStream("druid.properties");
           //创建Properties对象,用于加载流内部的数据
           Properties prop = new Properties();
           prop.load(is); //加载流内部的信息,以key-value的形式进行加载
           //调用静态方法,会自动给自己的属性赋值
           pool = DruidDataSourceFactory.createDataSource(prop);    
       } catch (Exception e) {
           System.out.println("注册驱动失败");
           e.printStackTrace();
       }
   }
   /**
    * 获取连接对象
    * @return 连接对象
    * @throws SQLException
    * @throws ClassNotFoundException
    */
   public static Connection getConnection() throws SQLException,
   ClassNotFoundException {

       //return DriverManager.getConnection(url, username, password);
       //从连接池中获取连接对象
       return pool.getConnection();
   }
   /**
    * 关闭数据库连接    
    * @param rs   结果集对象
    * @param stat 处理sql的执行对象Statement
    * @param conn 连接对象
    */
   public static void closeConnection(ResultSet rs, Statement stat, Connection conn) {
       try {
           if (rs != null) {
               rs.close();
           }
           if (stat != null) {
               stat.close();
           }
           if (conn != null) {
               conn.close();//释放连接,归还给连接池
           }
       } catch (Exception e) {
           System.out.println("数据库连接关闭失败");
           e.printStackTrace();
       }
   }
   public static void main(String[] args) throws ClassNotFoundException, SQLException {
       Connection conn = getConnection();
       System.out.println(conn);
       closeConnection(null, null, conn);
   }
}

五. DAO设计模式

5.1 DAO简介

- DAO是数据访问对象(Data Access Object)的简写。
- 建立在数据库与业务层之间,封装所有对数据库的访问操作,我们也可称之为持久层。
- 目的: 将数据访问逻辑和业务逻辑分开。

 

一个DAO设计模式包含以下内容

  1. 定义实体类: 通过对象关系映射(ORM)将数据库的表结构映射成java类型;表中的每一条记录映射成类的实例。用于数据的传 递。

  2. 定义一个接口: 在此接口中,定义应用程序对此表的所有访问操作,如增,删,改、查,等方法。

  3. 定义接口的实现类 实现接口中的所有抽象方法。

  4. 定义一个DAO工厂类型 用于返回接口实例 这样,开发人员只需要使用DAO接口即可,具体逻辑就变得透明了,无需了解内部细节。

扩展:项目的包名命名规则

规范: com.域名.项目名称.模块名称
com.qianfeng.jdbc03.util
com.qianfeng.jdbc03.entity
com.qianfeng.jdbc03.test
com.qianfeng.jdbc03.dao
com.qianfeng.jdbc03.dao.impl
com.qianfeng.jdbc03.service

5.2 DAO的案例示范

5.2.1 创建项目,导入相关资源
5.2.2 编写工具类DBUtil
5.2.3 编写实体类 import java.sql.Date;

import java.util.Objects;
/**
 * 以orm关系将数据库中的emp表映射成java中的Emp类型
 *  表的字段映射成类的属性
 */
public class Emp {
    private int empno;
    private String ename;
    private String job;
    private int mgr;
    private Date hiredate;
    private double salary;
    private double comm;
    private int deptno;
    public Emp(){}

    public Emp(int empno, String ename, String job, int mgr, Date hiredate, double salary, double comm, int deptno) {
        this.empno = empno;
        this.ename = ename;
        this.job = job;
        this.mgr = mgr;
        this.hiredate = hiredate;
        this.salary = salary;
        this.comm = comm;
        this.deptno = deptno;
    }

    public int getEmpno() {
        return empno;
    }

    public void setEmpno(int empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public int getMgr() {
        return mgr;
    }

    public void setMgr(int mgr) {
        this.mgr = mgr;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public double getComm() {
        return comm;
    }

    public void setComm(double comm) {
        this.comm = comm;
    }

    public int getDeptno() {
        return deptno;
    }

    public void setDeptno(int deptno) {
        this.deptno = deptno;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Emp emp = (Emp) o;
        return empno == emp.empno &&
            mgr == emp.mgr &&
            Double.compare(emp.salary, salary) == 0 &&
            Double.compare(emp.comm, comm) == 0 &&
            deptno == emp.deptno &&
            Objects.equals(ename, emp.ename) &&
            Objects.equals(job, emp.job) &&
            Objects.equals(hiredate, emp.hiredate);
    }

    @Override
    public int hashCode() {
        return Objects.hash(empno, ename, job, mgr, hiredate, salary, comm, deptno);
    }

    @Override
    public String toString() {
        return "Emp{" +
            "empno=" + empno +
            ", ename='" + ename + '\'' +
            ", job='" + job + '\'' +
            ", mgr=" + mgr +
            ", hiredate=" + hiredate +
            ", salary=" + salary +
            ", comm=" + comm +
            ", deptno=" + deptno +
            '}';
    }
}

5.2.4 定义接口

import com.qianfeng.jdbc03.entity.Emp;
import java.util.List;

/**
* 设计针对于实体类Emp和数据库里的emp表设计对数据库操作的接口
* 提供相应操作的抽象方法
*/
public interface EmpDao {
    /**
    * 提供向数据库中插入数据的方法,
    * @param e   面向对象思想可以使用实体类的实例
    */
    void addEmp(Emp e);
    /**
    * 提供删除数据库内的一条记录方法,通过id进行删除
    * @param empno   数据库表中的主键
    */
    void deleteById(int empno);

    /**
    * 修改方法。
    * @param e 传入前先设置成要修改的数据,然后传入方法中进行update语句赋值
    */
    void modifyEmp(Emp e);

    /**
    * 通过唯一键查询一条记录
    * @param empno
    * @return  封装成实体类实例
     */
    Emp findById(int empno);

    /**
    * 查询所有的记录。
     * @return  封装成类的实例,并存入集合
    */
    List<Emp> findAll();

    /**
    * 分页查询
    * @param page    要查询的页数
    * @param pageSize  每页显示的条数
    * @return  一页的所有记录,封装到集合中
    */
    List<Emp> findByPage(int page,int pageSize);
}

5.2.5 编写实现类

public class EmpDaoImpl implements EmpDao {
    @Override
    public void addEmp(Emp e) {
        Connection conn = null;
        PreparedStatement ps = null;
        try{
            conn = DBUtil.getConnection();
            String sql = "insert into emp values (?,?,?,?,?,?,?,?)";
            ps = conn.prepareStatement(sql);
            ps.setInt(1,e.getEmpno());
            ps.setString(2,e.getEname());
            ps.setString(3,e.getJob());
            ps.setInt(4,e.getMgr());
            ps.setDate(5,e.getHiredate());
            ps.setDouble(6,e.getSalary());
            ps.setDouble(7,e.getComm());
            ps.setInt(8,e.getDeptno());
            ps.executeUpdate();

        }catch (Exception e1){
            e1.printStackTrace();
        }finally{
            DBUtil.closeConnection(conn,ps,null);
        }
    }

    @Override
    public void deleteById(int empno) {

    }

    @Override
    public void modifyEmp(Emp e) {

    }

    @Override
    public Emp findById(int empno) {
        return null;
    }

    @Override
    public List<Emp> findAll() {
        return null;
    }

    @Override
    public List<Emp> findByPage(int page, int pageSize) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<Emp> emps = new ArrayList<Emp>();
        try{
            conn = DBUtil.getConnection();
            String sql = "select * from emp order by empno limit ?,?";
            ps = conn.prepareStatement(sql);
            ps.setInt(1,(page-1)*pageSize);
            ps.setInt(2,pageSize);

            rs = ps.executeQuery();
            Emp e = null;
            while(rs.next()){
                int empno = rs.getInt(1);
                String ename = rs.getString(2);
                String job = rs.getString("job");
                int mgr = rs.getInt("mgr");
                Date hiredate = rs.getDate("hiredate");
                double salary = rs.getDouble("sal");
                double comm = rs.getDouble("comm");
                int deptno = rs.getInt("deptno");
                e = new Emp(empno,ename,job,mgr,hiredate,salary,comm,deptno);
                emps.add(e);
            }
        }catch (Exception e1){
            e1.printStackTrace();
        }finally{
            DBUtil.closeConnection(conn,ps,rs);
        }
        return emps;
    }
}

5.2.6 编写DAO工厂类

public class DaoFactory{
    //定义属性EmpDao属性
   private static EmpDao empdao = new EmpDaoImpl();
   //让构造函数为 private,这样该类就不会被实例化
   private DaoFactory(){}
   public synchronized static EmpDao getInstance(){
       return empdao;
   }
}

5.2.7 编写测试类

public class TestDao {
   @Test
   public void testAddEmp(){
       EmpDao dao = DaoFactory.getInstance();
       Emp e = new Emp(9007,"huanghua","manager",7369,
                       Date.valueOf("2019-1-1"),3000.0,200.0,20);
       dao.addEmp(e);
   }
   @Test
   public void testFindByPage(){
       EmpDao dao = DaoFactory.getInstance();
       List<Emp> emps = dao.findByPage(3,5);
       for(Emp e:emps){
           System.out.println(e);
       }
   }
}

六 dbutils第三方工具类的使用

6.1 简介

- 此工具封装了DAO层(持久层)的逻辑。减少了开发周期。
- jar包:commons-dbutils-1.7.jar
- 常用API:
1. QueryRunner类型:可以直接使用连接池技术来操作数据库,进行增删改查
  构造器:QueryRunner(DataSource ds)
         返回一个指定数据库连接池得QueryRunner对象
  非静态方法:query(String sql, ResultSetHandler<T> rsh)
            通过sql,及其ReusltSetHandler的子类型来获取数据并封装成相应对象
2. ResultSetHandler:关于结果集的一个接口。
    其实现类如下:
    BeanHandler:将查询到的数据的第一条封装成实体类对象
    BeanListHandler:将查询到的数据的第一条封装成实体类对象的集合

6.2 代码测试:

public class Testdbutils {
   @Test
   public void testFindOne() throws SQLException {
       QueryRunner qr = new QueryRunner(DBUtil.getPool());
       Emp emp = qr.query("select * from emp",new BeanHandler<Emp>(Emp.class));
       System.out.println(emp);
   }
   @Test
   public void testFindOneParam() throws SQLException {
       QueryRunner qr = new QueryRunner(DBUtil.getPool());
       Emp emp = qr.query("select * from emp where empno =?",
                          new BeanHandler<Emp>(Emp.class),9007);
       System.out.println(emp);
   }
   @Test
   public void testFindAll() throws SQLException {
       QueryRunner qr = new QueryRunner(DBUtil.getPool());
       List<Emp> emp = qr.query("select * from emp",
                                new BeanListHandler<Emp>(Emp.class));
       System.out.println(emp);
   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值