JDBC学习笔记(1)—B站尚硅谷宋红康
JDBC学习笔记(2)—B站尚硅谷宋红康
举例说明:
AA有1000元,BB有1000元
AA给BB转账100
情况一:转账成功:AA-100元后有900元,BB+100元后有1100元,两个操作同时成功。
情况二:转账失败:AA和BB都还是1000元。假如AA转了100元,但是出了问题没转过去,那么就要回滚到最初的状态,不能是情况三。
情况三:转账失败:AA有900元,但是BB还是1000元
事务:就是情况一和情况二,要么成功,要么失败回到最初的状态。
AA-100元和BB+100元 合起来就是一个事务,作为一个工作单元执行。
一组逻辑操作单元:一条或多条sql语句
使数据从一种状态变成另一种状态:1000--->900 1000--->1100
如果失败,就要回滚rollback到最初的状态;
而回滚rollback是回到上一次提交的地方,因为有些操作是自动提交,所以可能无法回到最初的状态;
所以要找出所有会自动提交的操作,然后将其设置为不自动提交。
package com.atguigu5.transanction;
import com.atguigu3.util.JDBCUtils;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TransactionTest {
//针对数据表user_table,AA向BB转账100元
//*******************************未考虑事务**********************************************
//通用的增删改操作(未考虑事务)
public void update(String sql,Object ...agrs){
Connection connection = null;
PreparedStatement ps = null;
try{
//1.获取数据库连接
connection = JDBCUtils.getConnection();
//2.预编译sql语句(由形参传入),返回PreparedStatement对象实例
ps = connection.prepareStatement(sql);
//3.填充占位符
for (int i = 0; i < agrs.length; i++) {
ps.setObject(i+1,agrs[i]);
}
//4.执行
ps.execute();
}catch (Exception e){
e.printStackTrace();
}finally {
//5.释放资源
JDBCUtils.closeResource(connection,ps);
}
}
@Test
//未考虑事务
public void testUpdate(){
String sql1 = "update user_table set balance = balance - 100 where user = ?";
update(sql1,"AA");
String sql2 = "update user_table set balance = balance + 100 where user = ?";
update(sql2,"BB");
System.out.println("转账成功");
}
//*******************************考虑事务**********************************************
/*
考虑事务:
如果出错了要能够回滚到最初的状态。
怎么做?把所有能够自动提交的操作设置为不能自动提交。
分析这个转账问题:发现需要解决两个自动提交问题,一个是DML(即update语句)自动提交,一个是关闭连接会自动提交。
解决:关闭连接就会自动提交问题
上面未考虑事务的逻辑:
有两个sql操作:两次连接
---获取连接1---
***执行1***
---关闭连接1--- 这里会自动提交
---获取连接2---
***执行2***
---关闭连接2---
所以要改为:改为一次连接
---获取连接---
***执行1***
***执行2***
---关闭连接---
解决:DML语句自动提交问题
1.取消DML自动提交:
conn.setAutoCommit(false);
2.操作成功之后手动提交:
conn.commit();
3.操作不成功回滚:
conn.rollback();
*/
//通用的增删改操作(考虑事务)
//该方法可以返回void,
//也可以返回int。如果想要看所作操作影响了几条数据,可以使用return ps.executeUpdate(); 然后方法返回int。
public int update(Connection conn,String sql,Object ...agrs){
PreparedStatement ps = null;
try{
//1.预编译sql语句(由形参传入),返回PreparedStatement对象实例
ps = conn.prepareStatement(sql);
//2.填充占位符
for (int i = 0; i < agrs.length; i++) {
ps.setObject(i+1,agrs[i]);
}
//3.执行
return ps.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally {
//4.释放资源
JDBCUtils.closeResource(null,ps);
}
//这个别忘了
return 0;
}
@Test
//测试:考虑事务
public void testUpdateWithTx(){
Connection conn = null;
try{
//1.自己开连接
conn = JDBCUtils.getConnection();
//2.取消DML自动提交
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("转账成功");
//3.提交数据(操作成功)
conn.commit();
}catch (Exception e){
e.printStackTrace();
//4.提交出现问题(回滚)
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}finally {
//5.恢复自动提交机制
/*
在某些时候,尤其是在数据库连接池中,数据库连接池中有很多连接,
一个连接可能会被多个事务使用,一个事务不需要自动提交,但是下一个事务可能需要自动提交,所以要恢复自动提交机制
*/
try {
conn.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
//6.自己关连接
JDBCUtils.closeResource(conn,null);
}
}
}
READ UNCOMMITTED 没有解决任何问题
READ COMMITTED 解决了脏读问题
REPEATABLE READ 解决了脏读和不可重复读问题
SERIALIZABLE 解决了脏读、不可重复读和幻读问题,但性能太差(一致性最好,但并发性较差)
一般使用 READ COMMITTED 和 REPEATABLE READ
一般是数据提交之后 才允许用户读
java代码中如何设置隔离级别?
alt + 7 可以看到一个类或接口的所有方法和属性等
java里面用数字代表隔离级别
mysql查看当前隔离级别:select@@transaction_isolation;
mysql默认的隔离级别是:REPEATABLE-READ
java中的Dao是什么意思
package com.atguigu6.dao;
import com.atguigu3.util.JDBCUtils;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
//封装了针对数据表的通用的操作(考虑事务):通用的增删改操作,通用的查操作
//BaseDAO 基础DAO,父类DAO
//设置为抽象类,无法实例化,虽然里面没有抽样方法
public abstract class BaseDAO {
//通用的增删改操作(考虑事务)(也应该可以用于表结构的创建删除和修改)
//该方法可以返回void,
//也可以返回int。如果想要看所作操作影响了几条数据,可以使用return ps.executeUpdate(); 然后方法返回int。
public int update(Connection conn, String sql, Object ...agrs){
PreparedStatement ps = null;
try{
//1.预编译sql语句(由形参传入),返回PreparedStatement对象实例
ps = conn.prepareStatement(sql);
//2.填充占位符
for (int i = 0; i < agrs.length; i++) {
ps.setObject(i+1,agrs[i]);
}
//3.执行
return ps.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally {
//4.释放资源
JDBCUtils.closeResource(null,ps);
}
//这个别忘了
return 0;
}
//通用的查操作操作,返回数据表中的一条记录(考虑事务)
public <T> T getInstance(Connection conn,Class<T> clazz,String sql, Object ...args){
PreparedStatement ps = null;
ResultSet rs = null;
try{
//1.获取数据库连接
conn = JDBCUtils.getConnection();
//2.预编译sql语句(有参数传递),返回PreparedStatement对象实例
ps = conn.prepareStatement(sql);
//3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1,args[i]);
}
//4.执行,并返回结果集
rs = ps.executeQuery();
//5.处理结果集
//获取结果集的元数据
ResultSetMetaData rsmd = rs.getMetaData();
//获取列数
int columnCount = rsmd.getColumnCount();
//这里演示获取一条数据,使用if
if (rs.next()){
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
//获取每个列的列值:通过ResultSet
Object columnValue = rs.getObject(i+1);
//获取每个列的列名的别名:通过ResultSetMetaData的getColumnLabel()方法
String columnLabel = rsmd.getColumnLabel(i+1);
//通过反射:为clazz对象的columnLabel属性 赋值为 columnValue (即clazz类中的set方法)
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columnValue);
}
return t;
}
}catch (Exception e){
e.printStackTrace();
}finally {
//6.关闭资源
JDBCUtils.closeResource(null,ps,rs);
}
//结果集中什么都没有,返回null
return null;
}
//通用的查操作操作,返回数据表中的多条记录(考虑事务)
public <T> List<T> getForList(Connection conn,Class<T> clazz, String sql, Object ...args){
PreparedStatement ps = null;
ResultSet rs = null;
try{
//1.获取数据库连接
conn = JDBCUtils.getConnection();
//2.预编译sql语句(有参数传递),返回PreparedStatement对象实例
ps = conn.prepareStatement(sql);
//3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1,args[i]);
}
//4.执行,并返回结果集
rs = ps.executeQuery();
//5.处理结果集
//获取结果集的元数据
ResultSetMetaData rsmd = rs.getMetaData();
//获取列数
int columnCount = rsmd.getColumnCount();
//创建集合对象
List<T> list = new ArrayList<T>();
while (rs.next()){
T t = clazz.newInstance();
//给t对象指定的属性赋值
for (int i = 0; i < columnCount; i++) {
//获取每个列的列值:通过ResultSet
Object columnValue = rs.getObject(i+1);
//获取每个列的列名的别名:通过ResultSetMetaData的getColumnLabel()方法
String columnLabel = rsmd.getColumnLabel(i+1);
//通过反射:为t对象的columnLabel属性 赋值为 columnValue (即T类中的set方法)
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columnValue);
}
list.add(t);
}
//这里return list;写在while外面
return list;
}catch (Exception e){
e.printStackTrace();
}finally {
//6.关闭资源
JDBCUtils.closeResource(null,ps,rs);
}
//结果集中什么都没有,返回null
return null;
}
//用于查询特殊值的通用方法(考虑事务),比如:select count(*) from user_table; 只有一列
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 (Exception e){
e.printStackTrace();
}finally {
//关闭资源
JDBCUtils.closeResource(null,ps,rs);
}
return null;
}
}
针对不同的表,写不同的具体的DAO
具体的DAO按说写一个类继承BaseDAO就好了
但是为了让结构更加规范,写一个接口规范,然后写一个类实现该接口并继承BaseDAO
package com.atguigu6.dao;
import com.atguigu6.bean.Customer;
import java.sql.Connection;
import java.sql.Date;
import java.util.List;
//此接口用于规范针对于customers表的常用操作
public interface CustomerDAO {
//定义一些抽象方法
//增:将customer对象添加到数据表中
void insert(Connection conn, Customer customer);
//删:针对指定的id,删除表中的一条记录
void deleteById(Connection conn,int id);
//改:针对内存中的customer对象,去修改数据表中指定的记录
//修改指定的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);
}
package com.atguigu6.bean;
import java.util.Date;
/*
ORM编程思想(object relational mapping)
一个表对应一个java类
表中的一条数据对应java类的一个对象
表中的一个字段对应java类的一个属性
*/
public class Customer {
private int id;
private String name;
private String email;
private Date birth;
public Customer() {
}
public Customer(int id, String name, String email, Date birth) {
this.id = id;
this.name = name;
this.email = email;
this.birth = birth;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", birth=" + birth +
'}';
}
}
package com.atguigu6.dao;
import com.atguigu6.bean.Customer;
import java.sql.Connection;
import java.sql.Date;
import java.util.List;
//对于接口CustomerDAO的实现类
public class CustomerDAOImpl extends BaseDAO implements CustomerDAO{
@Override
//该方法可以返回值,不一定是void类型,看情况需要,update方法有返回值。
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> list = getForList(conn, Customer.class, sql);
return list;
}
@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);
}
}
写一个测试类,测试CustomerDAOImpl
在CustomerDAOImpl代码中 右键单击 选择 GO to ---> Test 即可快速生成测试类。
package com.atguigu6.dao;
import com.atguigu3.util.JDBCUtils;
import com.atguigu6.bean.Customer;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.Date;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
//写一个测试类,测试CustomerDAOImpl
class CustomerDAOImplTest {
CustomerDAOImpl dao = new CustomerDAOImpl();
@Test
void insert() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
//这里的new Customer(id,,,); id写不写都行,数据库里会自动编号。
Customer customer = new Customer(1,"李四","[email protected]", new Date(3298749136L));
//测试:向表中添加一个customer
dao.insert(conn,customer);
System.out.println("添加成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,null);
}
}
@Test
void deleteById() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
//测试:删除表中13号customer
dao.deleteById(conn,13);
System.out.println("删除成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,null);
}
}
@Test
void update() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
//这个id要去表中找,要修改哪个customer就找他的id
Customer customer = new Customer(18,"贝多芬","[email protected]",new Date(3298749136L));
//测试:修改表中18号customer的属性
dao.update(conn,customer);
System.out.println("修改成功");
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,null);
}
}
@Test
void getCustomerById() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
//测试:查看表中id为19号的customer
Customer customer = dao.getCustomerById(conn,19);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,null);
}
}
@Test
void getAll() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
//测试:查看表中所有的数据
List<Customer> list = dao.getAll(conn);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,null);
}
}
@Test
void getCount() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
//测试:表中的数据条数
Long count = dao.getCount(conn);
System.out.println("表中的数据条数为:" + count);
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,null);
}
}
@Test
void getMaxBirth() {
Connection conn = null;
try {
conn = JDBCUtils.getConnection();
//测试:获取最大生日
Date maxBirth = dao.getMaxBirth(conn);
System.out.println("最大生日为:" + maxBirth);
} catch (Exception e) {
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,null);
}
}
}
上面的方法也可以用,也可以不优化。
优化:
已经知道是对于customers表的操作,那么方法的参数中就不应该传Customer.class,把这个参数去掉。
即把Class clazz 去掉,通过泛型。
package com.atguigu6.daoyouhua;
import com.atguigu3.util.JDBCUtils;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
//封装了针对数据表的通用的操作(考虑事务):通用的增删改操作,通用的查操作
//BaseDAO 基础DAO,父类DAO
//设置为抽象类,无法实例化,虽然里面没有抽样方法
public abstract class BaseDAO<T> {
private Class<T> clazz = null;
//代码块
{
/*
删掉了Class clazz参数,就要想办法获得。
假如实现类CustomerDAOImpl继承BaseDAO,那么父类的泛型就是Customer类
实现类CustomerDAOImpl是子类,BaseDAO是父类
子类继承了父类,子类要获得父类的泛型,即获得clazz = Customer
如何获得?
*/
//获得当前this对象的带有泛型参数的直接父类和该父类的类型(this虽然写在BaseDAO里,但当new了一个子类时,this代表子类对象)
Type genericSuperclass = this.getClass().getGenericSuperclass();
//获得父类所有的泛型参数,将其整体作为一个对象
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
//获取父类的泛型参数,放在一个数组里(泛型参数可能有多个)
Type[] typeArguments = parameterizedType.getActualTypeArguments();
//泛型的第一个参数,即Customer
clazz = (Class<T>) typeArguments[0];
}
/*
以上也可以写在构造方法里:
public BaseDAO(){
}
*/
//通用的增删改操作(考虑事务)(也应该可以用于表结构的创建删除和修改)
//该方法可以返回void,
//也可以返回int。如果想要看所作操作影响了几条数据,可以使用return ps.executeUpdate(); 然后方法返回int。
public int update(Connection conn, String sql, Object ...agrs){
PreparedStatement ps = null;
try{
//1.预编译sql语句(由形参传入),返回PreparedStatement对象实例
ps = conn.prepareStatement(sql);
//2.填充占位符
for (int i = 0; i < agrs.length; i++) {
ps.setObject(i+1,agrs[i]);
}
//3.执行
return ps.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally {
//4.释放资源
JDBCUtils.closeResource(null,ps);
}
//这个别忘了
return 0;
}
//通用的查操作操作,返回数据表中的一条记录(考虑事务)
public T getInstance(Connection conn,String sql, Object ...args){
PreparedStatement ps = null;
ResultSet rs = null;
try{
//1.获取数据库连接
conn = JDBCUtils.getConnection();
//2.预编译sql语句(有参数传递),返回PreparedStatement对象实例
ps = conn.prepareStatement(sql);
//3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1,args[i]);
}
//4.执行,并返回结果集
rs = ps.executeQuery();
//5.处理结果集
//获取结果集的元数据
ResultSetMetaData rsmd = rs.getMetaData();
//获取列数
int columnCount = rsmd.getColumnCount();
//这里演示获取一条数据,使用if
if (rs.next()){
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
//获取每个列的列值:通过ResultSet
Object columnValue = rs.getObject(i+1);
//获取每个列的列名的别名:通过ResultSetMetaData的getColumnLabel()方法
String columnLabel = rsmd.getColumnLabel(i+1);
//通过反射:为clazz对象的columnLabel属性 赋值为 columnValue (即clazz类中的set方法)
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columnValue);
}
return t;
}
}catch (Exception e){
e.printStackTrace();
}finally {
//6.关闭资源
JDBCUtils.closeResource(null,ps,rs);
}
//结果集中什么都没有,返回null
return null;
}
//通用的查操作操作,返回数据表中的多条记录(考虑事务)
public List<T> getForList(Connection conn,String sql, Object ...args){
PreparedStatement ps = null;
ResultSet rs = null;
try{
//1.获取数据库连接
conn = JDBCUtils.getConnection();
//2.预编译sql语句(有参数传递),返回PreparedStatement对象实例
ps = conn.prepareStatement(sql);
//3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1,args[i]);
}
//4.执行,并返回结果集
rs = ps.executeQuery();
//5.处理结果集
//获取结果集的元数据
ResultSetMetaData rsmd = rs.getMetaData();
//获取列数
int columnCount = rsmd.getColumnCount();
//创建集合对象
List<T> list = new ArrayList<T>();
while (rs.next()){
T t = clazz.newInstance();
//给t对象指定的属性赋值
for (int i = 0; i < columnCount; i++) {
//获取每个列的列值:通过ResultSet
Object columnValue = rs.getObject(i+1);
//获取每个列的列名的别名:通过ResultSetMetaData的getColumnLabel()方法
String columnLabel = rsmd.getColumnLabel(i+1);
//通过反射:为t对象的columnLabel属性 赋值为 columnValue (即T类中的set方法)
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columnValue);
}
list.add(t);
}
//这里return list;写在while外面
return list;
}catch (Exception e){
e.printStackTrace();
}finally {
//6.关闭资源
JDBCUtils.closeResource(null,ps,rs);
}
//结果集中什么都没有,返回null
return null;
}
//用于查询特殊值的通用方法(考虑事务),比如:select count(*) from user_table; 只有一列
//这是泛型方法,上面T是泛型类。
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 (Exception e){
e.printStackTrace();
}finally {
//关闭资源
JDBCUtils.closeResource(null,ps,rs);
}
return null;
}
}
package com.atguigu6.daoyouhua;
import com.atguigu6.bean.Customer;
import java.sql.Connection;
import java.sql.Date;
import java.util.List;
//此接口用于规范针对于customers表的常用操作
public interface CustomerDAO {
//定义一些抽象方法
//增:将customer对象添加到数据表中
void insert(Connection conn, Customer customer);
//删:针对指定的id,删除表中的一条记录
void deleteById(Connection conn,int id);
//改:针对内存中的customer对象,去修改数据表中指定的记录
//修改指定的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);
}
package com.atguigu6.daoyouhua;
import com.atguigu6.bean.Customer;
import java.sql.Connection;
import java.sql.Date;
import java.util.List;
//对于接口CustomerDAO的实现类
public class CustomerDAOImpl extends BaseDAO<Customer> implements CustomerDAO {
@Override
//该方法可以返回值,不一定是void类型,看情况需要,update方法有返回值。
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,sql,id);
return customer;
}
@Override
public List<Customer> getAll(Connection conn) {
String sql = "select id,name,email,birth from customers";
List<Customer> list = getForList(conn,sql);
return list;
}
@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);
}
}
JAVA反射-getGenericSuperclass()用法
使用数据库连接池代替自己创建连接
package com.atguigu7.connection;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.SQLException;
//C3P0数据库连接池的两种实现方式
public class C3P0Connection {
//第一种实现方式:不推荐
@Test
//首先需要添加c3p0-0.9.5.5.jar包和mchange-commons-java-0.2.19.jar包
public void testGetConnection() throws Exception {
//该怎么使用?
//c3p0-0.9.1.2/doc/index.html文件中有使用方法
//获取C3P0数据库连接池
ComboPooledDataSource cpds = new ComboPooledDataSource();//获取连接池对象
cpds.setDriverClass("com.mysql.cj.jdbc.Driver");//设置数据库驱动
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/shangguigu_jdbc_test");//设置url
cpds.setUser("root");//用户
cpds.setPassword("abc123");//密码
//通过设置相关操作,对数据据连接池进行管理:
//比如:设置初始时数据库连接池中的连接数
cpds.setInitialPoolSize(10);
//还可以设置连接池中最大的连接数等
//获取连接
Connection conn = cpds.getConnection();
System.out.println(conn);
//销毁C3P0数据库连接池
//DataSources.destroy(cpds);
}
//第二种方式:使用配置文件:c3p0-config.xml(在src下创建,文件名只能是这个)
//推荐
@Test
public void testGetConnection1() throws SQLException {
ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
Connection conn = cpds.getConnection();
System.out.println(conn);
}
}
c3p0-config.xml:
<c3p0-config>
<named-config name="helloc3p0">
<property name="driverClass">com.mysql.cj.jdbc.Driverproperty>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/shangguigu_jdbc_testproperty>
<property name="user">rootproperty>
<property name="password">abc123property>
<property name="acquireIncrement">5property>
<property name="initialPoolSize">10property>
<property name="minPoolSize">10property>
<property name="maxPoolSize">100property>
<property name="maxStatements">50property>
<property name="maxStatementsPerConnection">2property>
named-config>
c3p0-config>
测试:
package com.atguigu7.connection;
import com.atguigu6.bean.Customer;
import com.atguigu6.dao.CustomerDAOImpl;
import com.atguigu7.util.newJDBCUtils;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.SQLException;
public class Test {
//将第二种方式封装起来newJDBCUtils,测试c3p0连接池获取连接
@Test
public void testGetCustomerById(){
CustomerDAOImpl dao = new CustomerDAOImpl();
Connection conn = null;
try {
conn = newJDBCUtils.getConnection1();
Customer customer = dao.getCustomerById(conn,19);
System.out.println(customer);
} catch (SQLException e) {
e.printStackTrace();
}finally {
newJDBCUtils.closeResource(conn,null);
}
}
}
package com.atguigu7.util;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.*;
public class newJDBCUtils {
//获取连接:C3P0
//一个连接池,多个连接
private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
public static Connection getConnection1() throws SQLException {
Connection conn = cpds.getConnection();
return conn;
}
//关闭资源
//参数本来应该写PreparedStatement,但是PreparedStatement是Statement是子接口,
//所以写Statement范围更大点,既可以传PreparedStatement,也可以传Statement。
public static void closeResource(Connection connection, Statement ps){
try {
//关闭之前避免出现空指针
if (ps!=null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void closeResource(Connection connection, PreparedStatement ps, ResultSet resultSet){
try {
//关闭之前避免出现空指针
if (resultSet!=null){
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (ps!=null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
package com.atguigu7.connection;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.junit.jupiter.api.Test;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import java.util.ResourceBundle;
//DBCP数据库连接池
public class DBCPConnection {
//首先需要导入commons-dbcp2-2.9.0.jar和commons-pool2-2.11.1.jar包
//出错的话:还要导入commons-logging-1.2.jar包
/*
如何写?commons-dbcp2-2.9.0/apidocs/index.html文件有介绍
*/
@Test
//方式一:不推荐
public void testGetConnection() throws SQLException {
//创建DBCP数据库连接池
BasicDataSource source = new BasicDataSource();
//设置基本信息
source.setDriverClassName("com.mysql.cj.jdbc.Driver");
source.setUrl("jdbc:mysql://localhost:3306/shangguigu_jdbc_test");
source.setUsername("root");
source.setPassword("abc123");
//还可以设置其他涉及数据库连接池管理的相关属性
source.setInitialSize(10);//设置初始化连接数
source.setMaxTotal(10);//设置连接池可同时连接的最大的连接数
Connection conn = source.getConnection();
System.out.println(conn);
}
//方式二(推荐):使用配置文件dbcp.properties(src路径下)
@Test
public void testGetConnection1() throws Exception{
Properties pros = new Properties();
pros.load(new FileInputStream("src/dbcp.properties"));
DataSource source = BasicDataSourceFactory.createDataSource(pros);
Connection conn = source.getConnection();
System.out.println(conn);
}
}
dbcp.properties:
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/shangguigu_jdbc_test
username=root
password=abc123
#其他配置也可以写
initialSize=10
因版本问题,上面的属性有些改变了。
测试:
package com.atguigu7.connection;
import com.atguigu6.bean.Customer;
import com.atguigu6.dao.CustomerDAOImpl;
import com.atguigu7.util.newJDBCUtils;
import java.sql.Connection;
import java.sql.SQLException;
public class Test {
//C3P0:将第二种方式封装到newJDBCUtils,测试c3p0连接池获取连接
@org.junit.jupiter.api.Test
public void testGetCustomerById(){
CustomerDAOImpl dao = new CustomerDAOImpl();
Connection conn = null;
try {
conn = newJDBCUtils.getConnection1();
Customer customer = dao.getCustomerById(conn,19);
System.out.println(customer);
} catch (SQLException e) {
e.printStackTrace();
}finally {
newJDBCUtils.closeResource(conn,null);
}
}
//DBCP:将第二种方式封装到newJDBCUtils,测试DBCP连接池获取连接
@org.junit.jupiter.api.Test
public void testGetCustomerById1(){
CustomerDAOImpl dao = new CustomerDAOImpl();
Connection conn = null;
try {
conn = newJDBCUtils.getConnection2();
Customer customer = dao.getCustomerById(conn,19);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
newJDBCUtils.closeResource(conn,null);
}
}
}
package com.atguigu7.util;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
public class newJDBCUtils {
//获取连接:C3P0
//一个连接池,多个连接
private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
public static Connection getConnection1() throws SQLException {
Connection conn = cpds.getConnection();
return conn;
}
//获取连接:DBCP
private static DataSource source;
static {
try{
Properties pros = new Properties();
pros.load(new FileInputStream("src/dbcp.properties"));
//创建一个DBCP数据库连接池(一个连接池)
source = BasicDataSourceFactory.createDataSource(pros);
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection2() throws Exception{
Connection conn = source.getConnection();
return conn;
}
//关闭资源
//参数本来应该写PreparedStatement,但是PreparedStatement是Statement是子接口,
//所以写Statement范围更大点,既可以传PreparedStatement,也可以传Statement。
public static void closeResource(Connection connection, Statement ps){
try {
//关闭之前避免出现空指针
if (ps!=null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void closeResource(Connection connection, PreparedStatement ps, ResultSet resultSet){
try {
//关闭之前避免出现空指针
if (resultSet!=null){
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (ps!=null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
package com.atguigu7.connection;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.junit.jupiter.api.Test;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.util.Properties;
//Druid数据库连接池
public class DruidConnection {
//首先导入包druid-1.2.8.jar
//怎么写?查看文档index.html
@Test
//采用配置文件方式(src下的druid.properties)
public void testGetConnection() throws Exception{
Properties pros = new Properties();
pros.load(new FileInputStream("src/druid.properties"));
DataSource source = DruidDataSourceFactory.createDataSource(pros);
Connection conn = source.getConnection();
System.out.println(conn);
}
}
druid.properties:
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/shangguigu_jdbc_test
username=root
password=abc123
#可以设置其他属性
initialSize=10
maxActive=10
测试:
package com.atguigu7.connection;
import com.atguigu6.bean.Customer;
import com.atguigu6.dao.CustomerDAOImpl;
import com.atguigu7.util.newJDBCUtils;
import java.sql.Connection;
import java.sql.SQLException;
public class Test {
//C3P0:将第二种方式封装到newJDBCUtils,测试c3p0连接池获取连接
@org.junit.jupiter.api.Test
public void testGetCustomerById(){
CustomerDAOImpl dao = new CustomerDAOImpl();
Connection conn = null;
try {
conn = newJDBCUtils.getConnection1();
Customer customer = dao.getCustomerById(conn,19);
System.out.println(customer);
} catch (SQLException e) {
e.printStackTrace();
}finally {
newJDBCUtils.closeResource(conn,null);
}
}
//DBCP:将第二种方式封装到newJDBCUtils,测试DBCP连接池获取连接
@org.junit.jupiter.api.Test
public void testGetCustomerById1(){
CustomerDAOImpl dao = new CustomerDAOImpl();
Connection conn = null;
try {
conn = newJDBCUtils.getConnection2();
Customer customer = dao.getCustomerById(conn,19);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
newJDBCUtils.closeResource(conn,null);
}
}
//Druid:封装到newJDBCUtils,测试Druid连接池获取连接
@org.junit.jupiter.api.Test
public void testGetCustomerById2(){
CustomerDAOImpl dao = new CustomerDAOImpl();
Connection conn = null;
try {
conn = newJDBCUtils.getConnection3();
Customer customer = dao.getCustomerById(conn,19);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
newJDBCUtils.closeResource(conn,null);
}
}
}
package com.atguigu7.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mysql.cj.util.EscapeTokenizer;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
public class newJDBCUtils {
//获取连接:C3P0连接池
//一个连接池,多个连接
private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
public static Connection getConnection1() throws SQLException {
Connection conn = cpds.getConnection();
return conn;
}
//获取连接:DBCP连接池
private static DataSource source;
static {
try{
Properties pros = new Properties();
pros.load(new FileInputStream("src/dbcp.properties"));
//创建一个DBCP数据库连接池(一个连接池)
source = BasicDataSourceFactory.createDataSource(pros);
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection2() throws Exception{
Connection conn = source.getConnection();
return conn;
}
//获取连接:Druid连接池
private static DataSource source1;
static {
try{
Properties pros = new Properties();
pros.load(new FileInputStream("src/druid.properties"));
source1 = DruidDataSourceFactory.createDataSource(pros);
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection3() throws Exception{
Connection conn = source1.getConnection();
return conn;
}
//关闭资源
//参数本来应该写PreparedStatement,但是PreparedStatement是Statement是子接口,
//所以写Statement范围更大点,既可以传PreparedStatement,也可以传Statement。
public static void closeResource(Connection connection, Statement ps){
try {
//关闭之前避免出现空指针
if (ps!=null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void closeResource(Connection connection, PreparedStatement ps, ResultSet resultSet){
try {
//关闭之前避免出现空指针
if (resultSet!=null){
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (ps!=null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Apache下有一个DBUtils.jar包,可以实现增删改查操作
DBUtils代替了我们自己使用PreparedStatement写的通用的增删改查操作
快捷键ctrl+alt+t:对代码块进行try..catch...
package com.atguigu8.dbutils;
//DBUtils:
//首先要导入commons-dbutils-1.7.jar包
//怎么写?查看commons-dbutils-1.7\apidocs\index.html文件
import com.atguigu6.bean.Customer;
import com.atguigu7.util.newJDBCUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
//dbutils是Apache组织提供的一个开源JDBC工具类库,封装了针对数据库的增删改查操作
public class QueryRunnerTest {
/*
QueryRunner是DBUtils提供一个类:
该类有方法:
查询:query()
增删改:update()
*/
@Test
//插入一条数据
public void testInsert() {
//快捷键ctrl+alt+t:对代码块进行try..catch...
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = newJDBCUtils.getConnection3();
String sql = "insert into customers(name,email,birth) values(?,?,?)";
//update()方法有返回值,也可以不用,返回int,影响了几条数据
//update()有很多重载的方法,根据具体情况选择
int insertCount = runner.update(conn,sql,"王五","[email protected]","2001-09-09");
System.out.println("添加了" + insertCount + "条数据");
} catch (Exception e) {
e.printStackTrace();
} finally {
newJDBCUtils.closeResource(conn,null);
}
}
//删和改操作与增操作差不多,只不过sql语句不同
@Test
//查操作:返回一条数据
/*
query(Connection,sql,ResultSetHandler,...args);
ResultSetHandler是结果集处理器,这是一个接口,要使用它的实现类。
DBUtils提供了很多实现类,这里返回一个对象,使用:BeanHandler类
*/
//使用BeanHandler返回一个对象
public void testQuery1(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = newJDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
//查询id为23的customer
Customer customer = runner.query(conn, sql, handler, 23);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
newJDBCUtils.closeResource(conn,null);
}
}
@Test
//查操作:返回多条数据
//使用BeanListHandler返回多个个对象
public void testQuery2(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = newJDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id < ?";
BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);
//查询id小于23的customer
List<Customer> list = runner.query(conn, sql, handler, 23);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
newJDBCUtils.closeResource(conn,null);
}
}
/*
其他的ResultSetHandler的实现类:
ArrayHandler:返回一个数组对象
ArrayListHandler:返回多个数组对象
MapHandler:返回一个键值对
MapListHandler:返回多个键值对
*/
@Test
//演示MapHandler
public void testQuery3(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = newJDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
MapHandler handler = new MapHandler();
//查询id为23的customer
Map<String, Object> map = runner.query(conn, sql, handler, 23);
System.out.println(map);
} catch (Exception e) {
e.printStackTrace();
} finally {
newJDBCUtils.closeResource(conn,null);
}
}
@Test
//查询特殊值:select count(*) from customers
//使用ScalarHandler
public void testQuery4(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = newJDBCUtils.getConnection3();
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 {
newJDBCUtils.closeResource(conn,null);
}
}
@Test
//如果DBUtils提供的实现类无法满足要求:自定义ResultSetHandler实现类
public void testQuery5(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = newJDBCUtils.getConnection3();
String sql = "select id,name,email,birth from customers where id = ?";
//匿名实现类
ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>(){
@Override
public Customer handle(ResultSet resultSet) throws SQLException {
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,23);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
newJDBCUtils.closeResource(conn,null);
}
}
}
package com.atguigu7.util;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
public class newJDBCUtils {
//获取连接:C3P0连接池
//一个连接池,多个连接
private static ComboPooledDataSource cpds = new ComboPooledDataSource("helloc3p0");
public static Connection getConnection1() throws SQLException {
Connection conn = cpds.getConnection();
return conn;
}
//获取连接:DBCP连接池
private static DataSource source;
static {
try{
Properties pros = new Properties();
pros.load(new FileInputStream("src/dbcp.properties"));
//创建一个DBCP数据库连接池(一个连接池)
source = BasicDataSourceFactory.createDataSource(pros);
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection2() throws Exception{
Connection conn = source.getConnection();
return conn;
}
//获取连接:Druid连接池
private static DataSource source1;
static {
try{
Properties pros = new Properties();
pros.load(new FileInputStream("src/druid.properties"));
source1 = DruidDataSourceFactory.createDataSource(pros);
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection3() throws Exception{
Connection conn = source1.getConnection();
return conn;
}
//关闭资源
//参数本来应该写PreparedStatement,但是PreparedStatement是Statement是子接口,
//所以写Statement范围更大点,既可以传PreparedStatement,也可以传Statement。
public static void closeResource(Connection connection, Statement ps){
try {
//关闭之前避免出现空指针
if (ps!=null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void closeResource(Connection connection, PreparedStatement ps, ResultSet resultSet){
try {
//关闭之前避免出现空指针
if (resultSet!=null){
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (ps!=null){
ps.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
//关闭之前避免出现空指针
if (connection!=null){
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//使用DBUtils关闭资源
public static void closeResource1(Connection conn, PreparedStatement ps, ResultSet rs){
/*
方法一:
try {
DbUtils.close(rs);
} catch (SQLException e) {
e.printStackTrace();
}
try {
DbUtils.close(ps);
} catch (SQLException e) {
e.printStackTrace();
}
try {
DbUtils.close(conn);
} catch (SQLException e) {
e.printStackTrace();
}
*/
//方法二:
DbUtils.closeQuietly(rs);
DbUtils.closeQuietly(ps);
DbUtils.closeQuietly(conn);
}
}
不考虑事务的写法(考虑事务看第6章):
Customer类(具体看情况是哪个类)
package com.lastcode.bean;
import java.util.Date;
/*
ORM编程思想(object relational mapping)
一个表对应一个java类
表中的一条数据对应java类的一个对象
表中的一个字段对应java类的一个属性
*/
public class Customer {
private int id;
private String name;
private String email;
private Date birth;
public Customer() {
}
public Customer(int id, String name, String email, Date birth) {
this.id = id;
this.name = name;
this.email = email;
this.birth = birth;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", birth=" + birth +
'}';
}
}
因为要使用@Test 测试,还要导入:
#该配置文件要写在src路径下
driverClassName=com.mysql.cj.jdbc.Driver
#shangguigu_jdbc_test 是自己创建的数据库
url=jdbc:mysql://localhost:3306/shangguigu_jdbc_test
username=root
password=abc123
#可以设置其他属性
initialSize=10
maxActive=10
JDBCUtils类
//封装获取连接和关闭资源操作
//通过Druid数据库连接池获取数据库连接
//通过DBUtils关闭资源
package com.lastcode;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import org.apache.commons.dbutils.DbUtils;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;
//封装获取连接和关闭资源操作
//通过Druid数据库连接池获取数据库连接
//通过DBUtils关闭资源
public class JDBCUtils {
//获取数据库连接
private static DataSource source;
static {
try{
Properties pros = new Properties();
pros.load(new FileInputStream("src/druid.properties"));
source = DruidDataSourceFactory.createDataSource(pros);
}catch (Exception e){
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception{
Connection conn = source.getConnection();
return conn;
}
//关闭资源
public static void closeResource(Connection conn, PreparedStatement ps, ResultSet rs){
/*
方法一:
try {
DbUtils.close(rs);
} catch (SQLException e) {
e.printStackTrace();
}
try {
DbUtils.close(ps);
} catch (SQLException e) {
e.printStackTrace();
}
try {
DbUtils.close(conn);
} catch (SQLException e) {
e.printStackTrace();
}
*/
//方法二:
DbUtils.closeQuietly(rs);
DbUtils.closeQuietly(ps);
DbUtils.closeQuietly(conn);
}
}
DBUtils类
package com.lastcode;
import com.atguigu6.bean.Customer;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
//使用DBUtils完成增删改查操作
/*
1.QueryRunner是DBUtils提供一个类:
该类有方法:
查询:query()
增删改:update()
2.ResultSetHandler是结果集处理器,也是DBUtils提供一个类,这是一个接口,要使用它的实现类。
query(Connection,sql,ResultSetHandler,...args);
DBUtils提供了很多实现类:
返回一个对象,使用:BeanHandler类
使用BeanListHandler返回多个个对象
ArrayHandler:返回一个数组对象
ArrayListHandler:返回多个数组对象
MapHandler:返回一个键值对
MapListHandler:返回多个键值对
查询特殊值:select count(*) from customers
使用ScalarHandler
*/
public class DBUtilsTest {
@Test
//1.插入一条数据
public void testInsert() {
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = JDBCUtils.getConnection();
String sql = "insert into customers(name,email,birth) values(?,?,?)";
//update()方法有返回值,也可以不用,返回int,影响了几条数据
//update()有很多重载的方法,根据具体情况选择
int insertCount = runner.update(conn,sql,"王五","[email protected]","2001-09-09");
System.out.println("添加了" + insertCount + "条数据");
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null,null);
}
}
//2.删和改操作与增操作差不多,只不过sql语句不同
@Test
//3.查操作:返回一条数据
//使用BeanHandler返回一个对象
public void testQuery1(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = JDBCUtils.getConnection();
String sql = "select id,name,email,birth from customers where id = ?";
BeanHandler<Customer> handler = new BeanHandler<>(Customer.class);
//查询id为23的customer
Customer customer = runner.query(conn, sql, handler, 23);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null,null);
}
}
@Test
//4.查操作:返回多条数据
//使用BeanListHandler返回多个个对象
public void testQuery2(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = JDBCUtils.getConnection();
String sql = "select id,name,email,birth from customers where id < ?";
BeanListHandler<Customer> handler = new BeanListHandler<>(Customer.class);
//查询id小于23的customer
List<Customer> list = runner.query(conn, sql, handler, 23);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null,null);
}
}
@Test
//5.查询特殊值:select count(*) from customers
//使用ScalarHandler
public void testQuery3(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = JDBCUtils.getConnection();
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,null);
}
}
@Test
//6.如果DBUtils提供的实现类无法满足要求:自定义ResultSetHandler实现类
public void testQuery5(){
Connection conn = null;
try {
QueryRunner runner = new QueryRunner();
//通过druid获取连接
conn = JDBCUtils.getConnection();
String sql = "select id,name,email,birth from customers where id = ?";
//匿名实现类
ResultSetHandler<Customer> handler = new ResultSetHandler<Customer>(){
@Override
public Customer handle(ResultSet resultSet) throws SQLException {
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,23);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,null,null);
}
}
}