这里写目录标题
JDBC连接池
连接池–存储连接
连接池是一种常用的技术,为什么需要连接池呢?这个需要从TCP说起。假如我们的服务器跟数据库没有部署在同一台机器,那么,服务器每次查询数据库都要先建立连接,一般都是TCP链接,建立连接就需要3次握手了,假设后台服务跟数据库的单程的访问时间需要10ms,那么光是建立连接就花了30ms,并且TCP还有慢启动的机制,实际上一次查询可能还不止1次TCP来回,查询效率就会大大降低。
好处
- 在连接池中的连接, 在连接池初始化时就已经创建好
在使用连接的时候, 就可以快速获得连接对象 - 连接使用完成后, 可以将连接归还给连接池, 让连接重复使用
JDBC连接池规范
JDBC提供的连接池规范 DataSource
市面常见3种连接池
- Apache - dbcp
- c3p0
- alibaba - druid
c3p0连接池
- 导入jar包
- 编写配置文件 c3p0-config.xml/c3p0.properties
位置: 必须在类路径的根目录中 -> src中 - 创建连接池对象 ComboPooledDataSource
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 使用配置文件 c3p0-config.xml 来指定连接池的参数/属性配置
// 在使用ComboPooledDataSource无参构造器创建这个连接池对象时, 会自动去读取c3p0-config.xml文件内容
// 读取完c3p0-config.xml 后, 使用的是default-config里的配置信息
// 有参构造器, 传入一个name, 使用的就是named-config="otherc3p0"
//DataSource dataSource = new ComboPooledDataSource("otherc3p0");
Connection conn = dataSource.getConnection();
System.out.println(conn);
druid连接池
- 导入jar包
- 编写配置文件
位置和名字都随意 - 通过工厂创建连接池对象
DruidDataSourceFactory.createDataSource(Properties)
// 创建一个属性集 Properties
Properties pros = new Properties();
pros.load(Demo01.class.getResourceAsStream("druid.properties"));
// Druid连接池提供了一个获得DataSource的工厂类
DataSource dataSource = DruidDataSourceFactory.createDataSource(pros);
Connection conn = dataSource.getConnection();
System.out.println(conn);
public void test05SelectAll() throws Exception {
String sql = "select * from emp";
Connection conn = DruidUtils.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
List<Emp> list = new ArrayList<>();
while (rs.next()) {
// 对象的封装很繁琐
Emp emp = new Emp();
emp.setEmpno(rs.getInt("empno"));
emp.setEname(rs.getString("ename"));
emp.setSal(rs.getDouble("sal"));
emp.setJob(rs.getString("job"));
emp.setComm(rs.getDouble("comm"));
emp.setHiredate(rs.getDate("hiredate"));
System.out.println(emp);
list.add(emp);
}
System.out.println(list.size());
}
DruidUtils工具类
DataSource数据源是一个实现了datasource接口的类,它实现了连接和连接池的功能
public class DruidUtils {
private static DataSource dataSource;
static {
Properties pro = new Properties();
try {
pro.load(DruidUtils.class.getResourceAsStream("druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static DataSource getDataSource() {
return dataSource;
}
public static Connection getConnection() {
try {
return dataSource.getConnection();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return null;
}
连接池关闭
- 通过连接池获得的连接关闭后, 连接对象返回给连接池, 并且引用设置为null。重新createStatement报错NullPointerException
- 通过JDBC获得的连接关闭后, 连接对象还在, 但是状态是"已关闭", 不能再使用。重新createStatement报错ConnectionIsClosedException
JdbcTemplate
Spring框架 简化操作,冗余代码
不需要释放资源,自动执行
API
update(sql)——DML
JdbcTemplate template = new JdbcTemplate(DruidUtils.getDataSource());
@Test
public void insertTest() {
// 执行DML的方法
String sql = "insert into emp(empno,ename,job,sal,comm,hiredate) values(?,?,?,?,?,?)";
template.update(sql,8000,"jack","CLERK",800,0,"2020-08-14");
}
@Test
public void updateTest() {
// 执行DML的方法
String sql = "update emp set ename=?,sal=?,job=?,comm=?,hiredate=? where empno=?";
template.update(sql,"jack james",800,"CLERK",100,"2020-08-14",8000);
}
@Test
public void deleteTest() {
// 执行DML的方法
String sql = "delete from emp where empno = ?";
template.update(sql,8000);
}
queryforMap(sql)——DQL
只能处理一条结果集,生成一个map,将列名作为key, 列中的数据作为value封装到map中
map -> JavaBean, 工具可以使用
public void findTest() {
// 执行DQL的方法
String sql = "select * from emp where empno=?";
Map<String, Object> map = template.queryForMap(sql, 7369);
// {empno=7369, ename=SMITH, job=CLERK, mgr=7902, hiredate=1980-12-17, sal=800, comm=null, deptno=20}
System.out.println(map);
}
queryforList(sql)——DQL
将查询出来的结果集,每一行封装为一个map, 再将这个map封装到list中
public void findTest1() {
// 执行DQL的方法
String sql = "select * from emp";
List<Map<String, Object>> list = template.queryForList(sql);
list.stream().forEach(System.out::println);
}
{empno=7369, ename=SMITH, job=CLERK, mgr=7902, hiredate=1980-12-17, sal=800, comm=null, deptno=20}
{empno=7499, ename=ALLEN, job=SALESMAN, mgr=7698, hiredate=1981-02-20, sal=1600, comm=300, deptno=30}
{empno=7521, ename=WARD, job=SALESMAN, mgr=7698, hiredate=1981-02-22, sal=1250, comm=500, deptno=30}
......
queryforObject(sql,class)——DQL
查询单列数据,并且将这一列数据, 转换成Class对应的类型对象
@Test
public void findTest2() {
// 执行DQL的方法
String sql = "select count(*) from emp";
Long count = template.queryForObject(sql, Long.class);
System.out.println(count);
}
//14
query(sql, RowMapper)——DQL
提供的实现类BeanPropertyRomMapper(class)
使用前提:自定义实体类中属性名与表中字段名一致,否则都是null
public void findTest3() {
// 执行DQL的方法
String sql = "select * from emp";
/**
* RowMapper: 将结果集进行封装处理, 通过mapRow进行处理
* query 得到的结果集ResultSet, 并且遍历结果集,
* 然后调用RowMapper中的mapRow方法对每一行结果进行封装处理
*/
List<Emp> list = template.query(sql, new RowMapper<Emp>() {
@Override
/**
* rs: 当前指向的那一行结果数据 rs.getString/Int..
* i: 当前遍历的次数 - 了解
* @return 将一行数据封装得到的对象
*/
public Emp mapRow(ResultSet rs, int i) throws SQLException {
Emp emp = new Emp();
emp.setEmpno(rs.getInt("empno"));
// emp.setEname(rs.getString("ename"));
emp.setSal(rs.getDouble("sal"));
emp.setJob(rs.getString("job"));
emp.setComm(rs.getDouble("comm"));
emp.setHiredate(rs.getDate("hiredate"));
return emp;
}
});
list.stream().forEach(System.out::println);
}
简化
public void findTest4() {
// 执行DQL的方法
String sql = "select * from emp";
/**
* RowMapper: 将结果集进行封装处理, 通过mapRow进行处理
* query 得到的结果集ResultSet, 并且遍历结果集,
* 然后调用RowMapper中的mapRow方法对每一行结果进行封装处理
*/
List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
list.stream().forEach(System.out::println);
MVC对于数据库的规范
M: Module - 业务模块 -> 操作数据库 DAO
Data Access Object
一张表emp, 对应一个实体类Emp, 再对应一个DAO-EmpDao
EmpDao中的方法, 就是操作数据库基本功能
再对应一个测试类, 测试Dao中的所有方法
例
public class EmpDao {
// 后期 template 的创建 交给 Spring框架来做
private JdbcTemplate template = new JdbcTemplate(DruidUtils.getDataSource());
public void insertEmp(Emp emp) {
// 执行DML的方法
String sql = "insert into emp(empno,ename,job,sal,comm,hiredate) values(?,?,?,?,?,?)";
// stmt.setDate(date);
template.update(sql, emp.getEmpno(), emp.getEmpno(), emp.getJob(), emp.getSal(), emp.getComm(), emp.getHiredate());
}
public void updateEmp(Emp e) {
// 执行DML的方法
String sql = "update emp set ename=?,sal=?,job=?,comm=?,hiredate=? where empno=?";
template.update(sql, e.getEname(), e.getSal(), e.getJob(), e.getComm(), e.getHiredate(), e.getEmpno());
}
public void deleteEmpById(int id) {
// 执行DML的方法
String sql = "delete from emp where empno = ?";
template.update(sql, id);
}
public Emp findEmpById(int id) {
// 执行DQL的方法
String sql = "select * from emp where empno=?";
List<Emp> list = template.query(sql, new BeanPropertyRowMapper<>(Emp.class), id);
// 如果id查不出来, 结果会不会有影响
if (list == null || list.size() == 0) {
return null;
}
return list.get(0);
}
public List<Emp> findAllEmp() {
// 执行DQL的方法
String sql = "select * from emp";
List<Emp> list = template.query(sql, new BeanPropertyRowMapper<>(Emp.class));
return list;
}
public long findCount() {
// 执行DQL的方法
String sql = "select count(*) from emp";
Long count = template.queryForObject(sql, Long.class);
return count;
}
测试
public class EmpDaoTest {
// 测试EmpDao中的方法
EmpDao ed = new EmpDao();
@Test
public void testFindById() {
Emp emp = ed.findEmpById(736);
System.out.println(emp);
}
}