JDBC总结
JDBC概述
-
数据的持久化
持久化(persistence):将数据保存到可掉电式存储设备中以供之后使用
-
JDBC的理解
JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API)
优点:
从开发者的角度:不需要关注具体的数据库的细节
从数据库厂商的角度:只需要提供标准的具体实现--数据库的驱动
数据库的连接
获取连接:
/*获取连接的方式
将数据库需要的四个基本信息声明在配置文件中,通过读取配置文件的方式获取连接
1. 实现了数据与代码分离--解耦
2. 如果需要修改配置文件信息,可以避免程序重新打包
*/
@Test
public void getConnection() throws Exception {
//1. 读取配置文件中的4个基本信息
InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
//2. 加载驱动
Class.forName(driverClass);
//3. 获取链接
Connection connection = DriverManager.getConnection(url, user, password);
System.out.println(connection);
}
配置文件:jdbc.properties(声明在工程的src下)
user=root
password=****
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=truejava
driverClass=com.mysql.jdbc.Driver
通用操作:JDBCUtils
package com.th1024.utils;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* 操作数据库的工具类
*
* @author TuHong
* @create 2021-03-09 10:32
*/
public class JDBCUtils {
/*
获取数据库的连接
*/
public static Connection getConnection() throws Exception {
//1. 读取配置文件中的4个基本信息
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties properties = new Properties();
properties.load(is);
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driverClass = properties.getProperty("driverClass");
//2. 加载驱动
Class.forName(driverClass);
//3. 获取连接
Connection connection = DriverManager.getConnection(url, user, password);
return connection;
}
/*
关闭连接和statement的操作
*/
public static void closeResource(Connection connection, Statement statement){
try {
if(statement != null)
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
/*
关闭资源的操作
*/
public static void closeResource(Connection connection, Statement statement, ResultSet resultSet){
try {
if(statement != null)
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(connection != null)
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(resultSet != null)
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Statement接口实现CRUD操作(了解)
代码演示:
// 使用Statement的弊端:需要拼写sql语句,并且存在SQL注入的问题
@Test
public void testLogin() {
Scanner scan = new Scanner(System.in);
System.out.print("用户名:");
String userName = scan.nextLine();
System.out.print("密 码:");
String password = scan.nextLine();
// SELECT user,password FROM user_table WHERE USER = '1' or ' AND PASSWORD = '='1' or '1' = '1';
String sql = "SELECT user,password FROM user_table WHERE USER = '" + userName + "' AND PASSWORD = '" + password
+ "'";
User user = get(sql, User.class);
if (user != null) {
System.out.println("登陆成功!");
} else {
System.out.println("用户名或密码错误!");
}
}
弊端:
-
存在拼串操作,繁琐
-
存在SQL注入问题
SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令(如:SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1'),从而利用系统的SQL引擎完成恶意行为的做法
-
Statement无法操作Blob类型变量,批量操作效率低
PreparedStatement替换Statement实现CRUD操作
-
PreparedStatement的理解
① PreparedStatement是Statement的子接口
② 预编译SQL语句
-
使用PreparedStatement完成通用的增、删、改操作
//通用的增删改操作 public void update(String sql,Object... args) { Connection connection = null; PreparedStatement ps = null; try { //1. 获取数据库的连接 connection = JDBCUtils.getConnection(); //2. 预编译sql语句,返回PreparedStatement实例 ps = connection.prepareStatement(sql); //3. 填充占位符 for (int i = 0; i < args.length; i++) { ps.setObject(i + 1,args[i]); } //4. 执行 ps.execute(); } catch (Exception e) { e.printStackTrace(); } finally { //5. 关闭资源 try { if(ps != null) ps.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } try { if(connection != null) connection.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } }
-
使用PreparedStatement完成通用的查询操作
/* 针对不同的表的通用的查询操作,返回一条记录 */ public <T>T getInstance(Class<T> tClass,String sql,Object... args){ Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) { ps.setObject(i + 1,args[i]); } rs = ps.executeQuery(); //获取结果集的元数据:ResultSetMetaData ResultSetMetaData rsmd = rs.getMetaData(); //通过ResultSetMetaData获取结果集中的列数 int columnCount = rsmd.getColumnCount(); if(rs.next()){ T t = tClass.newInstance(); //处理结果集一行数据中的每一个列 for (int i = 0; i < columnCount; i++) { //获取列值 Object columnValue = rs.getObject(i + 1); //获取列名或列的别名 String columnLabel = rsmd.getColumnLabel(i + 1); //给t对象指定的columnLabel属性,赋值为columnValue:通过反射 Field field = tClass.getDeclaredField(columnLabel); field.setAccessible(true); field.set(t,columnValue); } return t; } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResource(conn,ps,rs); } return null; }
/* 针对不同的表的通用的查询操作,返回多条记录 */ public <T> List<T> getInstances(Class<T> tClass, String sql, Object... args) { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) { ps.setObject(i + 1,args[i]); } rs = ps.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); //创建集合对象 ArrayList<T> list = new ArrayList<>(); while(rs.next()){ T t = tClass.newInstance(); //处理结果集一行数据中的每一个列,给t对象指定的属性赋值 for (int i = 0; i < columnCount; i++) { Object columnValue = rs.getObject(i + 1); String columnLabel = rsmd.getColumnLabel(i + 1); Field field = tClass.getDeclaredField(columnLabel); field.setAccessible(true); field.set(t,columnValue); } list.add(t); } return list; } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResource(conn,ps,rs); } return null; }
-
总结
两种思想:面向接口编程思想、
ORM编程思想(Object Relational Mapping)
- 一个数据表对应一个java类
- 表中的一条记录对应java类的一个对象
- 表中的一个字段对应java类的一个属性
两种技术:
使用结果集的元数据:ResultSetMetaData、
- getColumnCount():获取列数
- getColumnLabel():获取列的别名或列名
反射:
- 创建对应的运行时类的对象
- 在运行时,动态地调用指定的运行时类的属性、方法
PreparedStatement操作Blob类型的变量
-
写入操作的方法:setBlob(InputStream is)
-
读取操作的方法:
Blob blob = getBlob(int index);
InputStream is = blob.getBinaryStream();
-
具体的insert操作
/* 测试使用PreparedStatement操作Blob类型的数据 */ @Test public void testInsert() throws Exception { Connection conn = JDBCUtils.getConnection(); String sql = "insert into customers(name,email,birth,photo) values(?,?,?,?)"; PreparedStatement ps = conn.prepareStatement(sql); ps.setObject(1,"枫花恋"); ps.setObject(2,"123@qq.com"); ps.setObject(3,"1999-01-01"); FileInputStream fis = new FileInputStream(new File("fenghualian.jpg")); ps.setBlob(4,fis); ps.execute(); JDBCUtils.closeResource(conn,ps); }
-
具体的query操作
/* 查询数据表customers中Blob类型的字段 */ @Test public void testQuery() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; InputStream is = null; FileOutputStream fos = null; try { conn = JDBCUtils.getConnection(); String sql = "select id,name,email,birth,photo from customers where id = ?"; ps = conn.prepareStatement(sql); ps.setInt(1,23); rs = ps.executeQuery(); if(rs.next()){ //方式一 // int id = rs.getInt(1); // String name = rs.getString(2); // String email = rs.getString(3); // Date birth = rs.getDate(4); //方式二 int id = rs.getInt("id"); String name = rs.getString("name"); String email = rs.getString("email"); Date birth = rs.getDate("birth"); Customer customer = new Customer(id, name, email, birth); System.out.println(customer); //将Blob类型的字段下载下来,以文件的形式保存在本地 Blob photo = rs.getBlob("photo"); is = photo.getBinaryStream(); fos = new FileOutputStream("fenghualian1.jpg"); byte[] buffer = new byte[1024]; int len; while((len = is.read(buffer)) != -1){ fos.write(buffer,0,len); } } } catch (Exception e) { e.printStackTrace(); } finally { try { if(fos != null) fos.close(); } catch (IOException e) { e.printStackTrace(); } try { if(is != null) is.close(); } catch (IOException e) { e.printStackTrace(); } JDBCUtils.closeResource(conn,ps,rs); } }
PreparedStatement实现高效的批量操作
代码实现:
/*
批量插入的方式二:使用PreparedStatement
优化1:
1. addBatch()、executeBatch()、clearBatch()
2. MySQL服务器默认是关闭批处理的,需要一个参数,让MySQL开启批处理的支持
?rewriteBatchedStatements=true 写在配置文件的url后面
3. 使用更新的MySQL驱动:mysql-connector-java-5.1.37-bin.jar
优化2:设置连接不允许自动提交数据
*/
@Test
public void testInsert() {
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();
conn = JDBCUtils.getConnection();
conn.setAutoCommit(false);
String sql = "insert into goods(name) values(?)";
ps = conn.prepareStatement(sql);
for (int i = 1; i <= 20000; i++) {
ps.setObject(1,"name_" + i);
//1. “攒”sql
ps.addBatch();
if(i % 500 == 0){
//2. 执行Batch
ps.executeBatch();
//3. 清空Batch
ps.clearBatch();
}
// ps.execute();
}
//提交数据
conn.commit();
long end = System.currentTimeMillis();
System.out.println("花费的时间为" + (end - start));//未优化:12427--优化:1334
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,ps);
}
}
总结:
PreparedStatement与Statement的异同
- PreparedStatement是Statement的子接口
- 开发中使用PreparedStatement代替Statement
- PreparedStatement可以解决Statement存在的效率低下以及SQL注入问题
数据库事务
-
事务
一组逻辑操作单元,是数据从一种状态变换到另外一种状态
四大属性:ACID
原子性(Atomicity):原子性是指事务是一个不可分割的工作单元,事务中的操作要么都发生,要么都不发生
一致性(Consistency):事务必须使数据库从一个一致性状态变换到另一个一致性状态
隔离性(Isolation):事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能相互干扰
持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
-
事务处理的原则
保证所有事物都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式;一个事务中执行多个操作时,要么所有事务都被提交(commit),修改将永久地保存,要么放弃所有修改,整个事务回滚(rollback)到最初状态
说明:
① 数据一旦提交,就不可回滚
② 哪些操作会导致数据的自动提交
-
DDL操作一旦执行,都会自动提交
-
DML操作默认情况下,一旦执行就会自动提交
通过set autocommit = false的方式取消DML操作的自动提交
-
默认在关闭连接时,会自动提交数据
-
-
代码的体现
//考虑数据库事务之后的转账操作 @Test public void testUpdateWithTx() { Connection conn = null; try { conn = JDBCUtils.getConnection(); //取消数据的自动提交 conn.setAutoCommit(false); String sql1 = "update user_table set balance = balance - 100 where user = ?"; update(conn,sql1,"AA"); // //模拟网络阻塞 // System.out.println(10/0); String sql2 = "update user_table set balance = balance + 100 where user = ?"; update(conn,sql2,"BB"); System.out.println("转账成功"); //2. 提交数据 conn.commit(); } catch (Exception e) { e.printStackTrace(); //3. 回滚数据 try { if(conn != null) conn.rollback(); } catch (SQLException throwables) { throwables.printStackTrace(); } } finally { try { if(conn != null) conn.setAutoCommit(true); } catch (SQLException throwables) { throwables.printStackTrace(); } JDBCUtils.closeResource(conn,null); } }
-
考虑事务的通用增删改操作
public int update(Connection conn,String sql,Object... args) { PreparedStatement ps = null; try { //1. 预编译sql语句,返回PreparedStatement实例 ps = conn.prepareStatement(sql); //2. 填充占位符 for (int i = 0; i < args.length; i++) { ps.setObject(i + 1,args[i]); } //3. 执行 return ps.executeUpdate(); } catch (SQLException throwables) { throwables.printStackTrace(); } finally { //4. 资源的关闭 JDBCUtils.closeResource(null,ps); } return 0; }
-
考虑事务的通用查询操作
//通用的查询操作(考虑事务),返回数据表中的一条记录 public <T> T getInstance(Connection conn,Class<T> tClass,String sql,Object... args) { PreparedStatement ps = null; ResultSet rs = null; try { ps = conn.prepareStatement(sql); for (int i = 0; i < args.length; i++) { ps.setObject(i + 1,args[i]); } rs = ps.executeQuery(); ResultSetMetaData rsmd = rs.getMetaData(); int columnCount = rsmd.getColumnCount(); if(rs.next()){ T t = tClass.newInstance(); //处理结果集的一行数据的每一列 for (int i = 0; i < columnCount; i++) { Object columnValue = rs.getObject(i + 1); String columnLabel = rsmd.getColumnLabel(i + 1); Field field = tClass.getDeclaredField(columnLabel); field.setAccessible(true); field.set(t,columnValue); } return t; } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeResource(null,ps,rs); } return null; }
DAO及其子类
BaseDAO
package com.th1024.DAO;
import com.th1024.utils.JDBCUtils;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* DAO:data(base) access object
* 封装了针对数据表的通用的操作
*
* @author TuHong
* @create 2021-03-11 21:29
*/
public abstract class BaseDAO {
//通用的增删改操作
public int update(Connection conn, String sql, Object... args) {
PreparedStatement ps = null;
try {
//1. 预编译sql语句,返回PreparedStatement实例
ps = conn.prepareStatement(sql);
//2. 填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1,args[i]);
}
//3. 执行
return ps.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
//4. 资源的关闭
JDBCUtils.closeResource(null,ps);
}
return 0;
}
//通用的查询操作,用于返回数据表中的一条记录
public <T> T getInstance(Connection conn,Class<T> tClass,String sql,Object... args) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1,args[i]);
}
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
if(rs.next()){
T t = tClass.newInstance();
//处理结果集的一行数据的每一列
for (int i = 0; i < columnCount; i++) {
Object columnValue = rs.getObject(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
Field field = tClass.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columnValue);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(null,ps,rs);
}
return null;
}
//通用的查询操作,用于返回数据表中的多条记录构成的集合
public <T> List<T> getInstances(Connection conn,Class<T> tClass,String sql,Object... args) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1,args[i]);
}
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
//创建集合对象
ArrayList<T> list = new ArrayList<>();
while(rs.next()){
T t = tClass.newInstance();
for (int i = 0; i < columnCount; i++) {
Object columnValue = rs.getObject(i + 1);
String columnLabel = rsmd.getColumnLabel(i + 1);
Field field = tClass.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columnValue);
}
list.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(null,ps,rs);
}
return null;
}
//用于查询特殊值的通用方法
public <E> E getValue(Connection conn,String sql,Object... args) {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.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 (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.closeResource(null,ps,rs);
}
return null;
}
}
CustomerDAO
package com.th1024.DAO;
import com.th1024.bean.Customer;
import java.sql.Connection;
import java.sql.Date;
import java.util.List;
/**
* 此接口用于规范针对customers表的常用操作
*
* @author TuHong
* @create 2021-03-11 21:49
*/
public interface CustomerDAO {
/*
将customer对象添加到数组中
*/
void insert(Connection conn, Customer customer);
/*
针对指定的id,删除表中的一条记录
*/
void deleteById(Connection conn,int id);
/*
使用内存中的customer对象,修改数据表中指定的记录
*/
void update(Connection conn,Customer customer);
/*
根据指定的id查询得到对应的Customer对象
*/
Customer getCustomerById(Connection conn,int id);
/*
查询表中所有记录构成的集合
*/
List<Customer> getAll(Connection conn);
/*
返回数据表中的数据的条目数
*/
Long getCount(Connection conn);
/*
返回数据表中的最大的生日
*/
Date getMaxBirth(Connection conn);
}
CustomerDAOImpl
package com.th1024.DAO;
import com.th1024.bean.Customer;
import java.sql.Connection;
import java.sql.Date;
import java.util.List;
/**
* @author TuHong
* @create 2021-03-11 21:58
*/
public class CustomerDAOImpl extends BaseDAO implements CustomerDAO{
@Override
public void insert(Connection conn, Customer customer) {
String sql = "insert into customers(name,email,birth) values (?,?,?)";
update(conn,sql,customer.getName(),customer.getEmail(),customer.getBirth());
}
@Override
public void deleteById(Connection conn, int id) {
String sql = "delete from customers where id = ?";
update(conn,sql,id);
}
@Override
public void update(Connection conn, Customer customer) {
String sql = "update customers set name = ?,email = ?,birth = ? where id = ?";
update(conn,sql,customer.getName(),customer.getEmail(),customer.getBirth(),customer.getId());
}
@Override
public Customer getCustomerById(Connection conn, int id) {
String sql = "select id,name,email,birth from customers where id = ?";
Customer customer = getInstance(conn, Customer.class, sql, id);
return customer;
}
@Override
public List<Customer> getAll(Connection conn) {
String sql = "select id,name,email,birth from customers";
List<Customer> customers = getInstances(conn, Customer.class, sql);
return customers;
}
@Override
public Long getCount(Connection conn) {
String sql = "select count(*) from customers";
return getValue(conn, sql);
}
@Override
public Date getMaxBirth(Connection conn) {
String sql = "select max(birth) from customers";
return getValue(conn,sql);
}
}
数据库连接池(Druid数据库连接池)
导入jar包:druid-1.1.10.jar
具体实现:
//使用Druid数据库连接池获取连接
private static DataSource source;
static{
try {
Properties pros = new Properties();
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
pros.load(is);
source = DruidDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection1() throws Exception {
Connection conn = source.getConnection();
return conn;
}
配置文件:druid.properties(定义在src下)
url=jdbc:mysql://localhost:3306/test
username=root
password=****
driverClassName=com.mysql.jdbc.Driver
initialSize=10
maxActive=10
DBUtils提供的jar包实现CRUD操作
导入jar包:commons-dbutils-1.3.jar
使用QueryRunner测试增、删、改操作:
//测试插入
@Test
public void testInsert() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection1();
String sql = "insert into customers(name,email,birth) values(?,?,?)";
int insertCount = runner.update(conn, sql, "枫花恋", "fhl@qq.com", "1999-01-01");
System.out.println("添加了" + insertCount + "行数据");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
//测试修改
@Test
public void testUpdate() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection1();
String sql = "update customers set birth = ? where id = ?";
int count = runner.update(conn, sql, "1999-05-06", 24);
System.out.println("共" + count + "行受到影响");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
使用QueryRunner测试查询操作:
//测试查询
/*
BeanHandler:是ResultSetHandler接口的实现类,用于封装表中的一条记录
*/
@Test
public void testQuery1() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection1();
String sql = "select id,name,email,birth from customers where id = ?";
BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
Customer customer = runner.query(conn, sql, handler, 23);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/*
BeanListHandler:是ResultSetHandler接口的实现类,用于封装表中的多条记录
*/
@Test
public void testQuery2() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection1();
String sql = "select id,name,email,birth from customers where id < ?";
BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);
List<Customer> customerList = runner.query(conn, sql, handler, 23);
customerList.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/*
MapHandler:是ResultSetHandler接口的实现类,对应表中的一条记录
将字段及相应字段的值作为map中的key和value
*/
@Test
public void testQuery3() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection1();
String sql = "select id,name,email,birth from customers where id = ?";
MapHandler handler = new MapHandler();
Map<String, Object> map = runner.query(conn, sql, handler, 23);
System.out.println(map);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/*
MapListHandler:是ResultSetHandler接口的实现类,对应表中的多条记录
将字段及相应字段的值作为map中的key和value,并将这些map添加到list中
*/
@Test
public void testQuery4() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection1();
String sql = "select id,name,email,birth from customers where id < ?";
MapListHandler handler = new MapListHandler();
List<Map<String, Object>> mapList = runner.query(conn, sql, handler, 23);
mapList.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/*
ScalarHandler:用于查询特殊值
*/
@Test
public void testQuery5() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection1();
String sql = "select count(*) from customers";
ScalarHandler handler = new ScalarHandler();
Long count = (Long) runner.query(conn, sql, handler);
System.out.println(count);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
@Test
public void testQuery6() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection1();
String sql = "select max(birth) from customers";
ScalarHandler handler = new ScalarHandler();
Date maxBirth = (Date) runner.query(conn, sql, handler);
System.out.println(maxBirth);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
/*
自定义ResultSetHandler实现类
*/
@Test
public void testQuery7() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
conn = JDBCUtils.getConnection1();
String sql = "select id,name,email,birth from customers where id = ?";
ResultSetHandler<Customer> handler = resultSet -> {
if (resultSet.next()){
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String email = resultSet.getString("email");
Date birth = resultSet.getDate("birth");
Customer customer = new Customer(id,name,email,birth);
return customer;
}
return null;
};
Customer customer = runner.query(conn, sql, handler, 24);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null);
}
}
关闭资源:
/*
关闭资源的操作
使用dbutils.jar中提供的DbUtils工具类,实现资源的关闭
*/
public static void closeResource1(Connection connection, Statement statement, ResultSet resultSet){
// try {
// DbUtils.close(connection);
// } catch (SQLException throwables) {
// throwables.printStackTrace();
// }
// try {
// DbUtils.close(statement);
// } catch (SQLException throwables) {
// throwables.printStackTrace();
// }
// try {
// DbUtils.close(resultSet);
// } catch (SQLException throwables) {
// throwables.printStackTrace();
// }
DbUtils.closeQuietly(connection,statement,resultSet);
}