JDBC_SE
JDBC
JDBC概述
JDBC:Java Database Connectivity,它是代表一组独立于任何数据库管理系统(DBMS)的API,声明在java.sql与javax.sql包中,是SUN(现在Oracle)提供的一组接口规范。由各个数据库厂商来提供实现类,这些实现类的集合构成了数据库驱动jar。
即JDBC技术包含两个部分:
(1)java.sql包和javax.sql包中的API
因为为了项目代码的可移植性,可维护性,SUN公司从最初就制定了Java程序连接各种数据库的统一接口规范。这样的话,不管是连接哪一种DBMS软件,Java代码可以保持一致性。
(2)各个数据库厂商提供的jar
因为各个数据库厂商的DBMS软件各有不同,那么内部如何通过sql实现增、删、改、查等管理数据,只有这个数据库厂商自己更清楚,因此把接口规范的实现交给各个数据库厂商自己实现。
Java程序连接MySQL数据库
/*
1、模块添加了依赖的mysql驱动相关库
2、在内存中加载驱动类(可选)
更早版本mysql驱动类:org.gjt.mm.mysql.Driver
最近版本:com.mysql.jdbc.Driver
MySQL8.0版本:com.mysql.cj.jdbc.Driver
Class.forName("com.mysql.cj.jdbc.Driver");
3、连接数据库:通过DriverManager工具类获取数据库连接Connection的对象。
String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
MySQL8使用时,url需要加参数:serverTimezone=UTC,否则会报错:
Exception in thread "main" java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specifc time zone value if you want to utilize time zone support.
4、断开连接:使用close方法。
*/
import java.sql.Connection;
import java.sql.DriverManager;
public class TestJDBC {
public static void main(String[] args)throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC","root","123456");
System.out.println("conn = " + conn);
conn.close();
}
}
java实现增删改查
/*步骤:
1、模块添加了依赖的mysql驱动相关库
2、在内存中加载驱动类(可选)
Class.forName("com.mysql.cj.jdbc.Driver");
3、连接数据库
通过DriverManager工具类获取数据库连接Connection的对象。
String url = "jdbc:mysql://localhost:3306/test?serverTimezone=UTC";
Connection conn = DriverManager.getConnection(url, "root", "123456");
4、操作数据库
(1)通过Connection对象获取Statement或PreparedStatement对象
(2)通过Statement或PreparedStatement对象执行sql
执行增、删、改:int executeUpate()
执行查询:ResultSet executeQuery()
(3)如果服务器有查询结果返回,需要用ResultSet接收
遍历结果集的方法:
boolean next():判断是否还有下一行
getString(字段名或序号),getInt(字段名或序号),getObject(字段名或序号)
5、释放资源(close)
*/
添加数据
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class TestInsert {
public static void main(String[] args)throws Exception {
//把驱动类加载到内存中
Class.forName("com.mysql.cj.jdbc.Driver");
//B:获取数据库连接对象
String url = "jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection connection = DriverManager.getConnection(url,"root","123456");
//Connection ==> 网络编程的Socket
String sql = "insert into t_department values(null,'测试数据部门','测试数据部门简介')";//发给服务器的sql
PreparedStatement pst = connection.prepareStatement(sql);
//PreparedStatement ==> IO流 网络编程的socket.getOutputStream()发生数据用的
int len = pst.executeUpdate();
//返回sql影响的记录数
System.out.println(len>0 ? "添加成功" : "添加失败");
pst.close();
connection.close();
}
}
/*
mysql> select * from t_department;
+-----+--------------+------------------+
| did | dname | description |
+-----+--------------+------------------+
| 1 | 研发部 | 负责研发工作 |
| 2 | 人事部 | 负责人事管理工作 |
| 3 | 市场部 | 负责市场推广工作 |
| 4 | 财务部 | 负责财务管理工作 |
| 5 | 后勤部 | 负责后勤保障工作 |
| 6 | 测试部 | 负责测试工作 |
| 7 | 测试数据部门 | 测试数据部门简介 |
+-----+--------------+------------------+
7 rows in set (0.00 sec)
*/
修改数据
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class TestUpdate {
public static void main(String[] args)throws Exception {
//把驱动类加载到内存中
Class.forName("com.mysql.cj.jdbc.Driver");
//B:获取数据库连接对象
String url = "jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection connection = DriverManager.getConnection(url, "root", "123456");
//Connection ==> 网络编程的Socket
String sql = "update t_department set description = 'xx' where did = 7";//发给服务器的sql
PreparedStatement pst = connection.prepareStatement(sql);
//PreparedStatement ==> IO流 网络编程的socket.getOutputStream()发生数据用的
int len = pst.executeUpdate();
//返回sql影响的记录数
System.out.println(len > 0 ? "修改成功" : "修改失败");
pst.close();
connection.close();
}
}
/*
mysql> select * from t_department;
+-----+--------------+------------------+
| did | dname | description |
+-----+--------------+------------------+
| 1 | 研发部 | 负责研发工作 |
| 2 | 人事部 | 负责人事管理工作 |
| 3 | 市场部 | 负责市场推广工作 |
| 4 | 财务部 | 负责财务管理工作 |
| 5 | 后勤部 | 负责后勤保障工作 |
| 6 | 测试部 | 负责测试工作 |
| 7 | 测试数据部门 | xx |
+-----+--------------+------------------+
7 rows in set (0.00 sec)
*/
删除数据
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
public class TestDelete {
public static void main(String[] args)throws Exception {
//把驱动类加载到内存中
Class.forName("com.mysql.cj.jdbc.Driver");
//B:获取数据库连接对象
String url = "jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection connection = DriverManager.getConnection(url, "root", "123456");
//Connection ==> 网络编程的Socket
String sql = "delete from t_department where did = 7";//发给服务器的sql
PreparedStatement pst = connection.prepareStatement(sql);
//PreparedStatement ==> IO流 网络编程的socket.getOutputStream()发生数据用的
int len = pst.executeUpdate();
//返回sql影响的记录数
System.out.println(len > 0 ? "删除成功" : "删除失败");
pst.close();
connection.close();
}
}
/*
mysql> select * from t_department;
+-----+--------+------------------+
| did | dname | description |
+-----+--------+------------------+
| 1 | 研发部 | 负责研发工作 |
| 2 | 人事部 | 负责人事管理工作 |
| 3 | 市场部 | 负责市场推广工作 |
| 4 | 财务部 | 负责财务管理工作 |
| 5 | 后勤部 | 负责后勤保障工作 |
| 6 | 测试部 | 负责测试工作 |
+-----+--------+------------------+
6 rows in set (0.00 sec)
*/
查询数据
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/*
步骤:
1、一个项目引入一次数据库驱动jar就可以
2、建立数据库连接
(1)加载驱动类:通过Class类的forName方法注册驱动
(2)获取数据库连接
通过DriverManager类的静态方法获取数据库连接对象
3、通过数据库连接对象获取Statement或PreparedStatement对象,用来执行sql
4、通过Statement或PreparedStatement对象调用
(1)int executeUpdate():执行insert,update,delete等更新数据库数据的sql
(2)ResultSet executeQuery():执行select查询的sql,返回一个结果集
(3)boolean execute():可以用来执行DDL语句
遍历结果集ResultSet的方法:
boolean next():判断是否还有下一行
getString(字段名或序号),getInt(字段名或序号),getObject(字段名或序号)
*/
public class TestSelect {
public static void main(String[] args)throws Exception {
//把驱动类加载到内存中
Class.forName("com.mysql.cj.jdbc.Driver");
//B:获取数据库连接对象
String url = "jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection connection = DriverManager.getConnection(url, "root", "123456");
//Connection ==> 网络编程的Socket
String sql = "select * from t_department";//发给服务器的sql
PreparedStatement pst = connection.prepareStatement(sql);
//PreparedStatement ==> IO流 网络编程的socket.getOutputStream()发生数据用的
ResultSet resultSet = pst.executeQuery();//==>IO流 输入流,又像是集合和迭代器的集成
while(resultSet.next()){ //while循环一次,迭代一行,遍历一行
int did = resultSet.getInt("did");//get一次得到一个单元格的数据
String dname = resultSet.getString("dname");
String decription = resultSet.getString("description");
System.out.println(did +"\t" + dname +"\t" + decription);
}
resultSet.close();
pst.close();
connection.close();
}
}
轻松处理各种问题
避免sql拼接和注入问题可以用 “?”
/*
String sql = "select * from t_employee where eid = ? ";//不用拼接了
PreparedStatement pst = connection.prepareStatement(sql);
//给?指定值 ? 从1开始
pst.setObject(1, id);
*/
@Test
public void test02()throws Exception {
Scanner input = new Scanner(System.in);
System.out.print("请输入你要查询的员工的编号:");
String id = input.nextLine();
// 第一种正常输入:1
// 第二种恶意输入:1 or 1=1 第一个1表示员工编号, 后面 or 1= 1表示条件,而1=1是永远成立,其他条件全部失效
//把驱动类加载到内存中
Class.forName("com.mysql.cj.jdbc.Driver");
//B:获取数据库连接对象
String url = "jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC";
Connection connection = DriverManager.getConnection(url, "root", "123456");
//Connection ==> 网络编程的Socket
String sql = "select * from t_employee where eid = ? ";//不用拼接了
PreparedStatement pst = connection.prepareStatement(sql);
//给?指定值
pst.setObject(1, id);
//因为这里把 "2 or 1=1"当成一个整体赋值给eid
//select * from t_employee where eid = '2 or 1=1';
/*
eid字段是int类型,mysql在解析时,发现给eid赋值了字符串,会把字符串尽量转为int类型的值。
SELECT '2 or 1=1'+0; 得到结果是2。
select * from t_employee where eid = '2 or 1=1';
等价于
select * from t_employee where eid = 2;
*/
//执行查询
ResultSet rs = pst.executeQuery();
/*
ResultSet接口提供了
(1)boolean next():判断是否有下一条记录
(2)获取某个单元格的数据
String getString(字段名)
int getInt(字段名)
double getDouble(字段名)
...
有点麻烦,需要一一去对应字段名
Object getObject(字段名)
Object getObject(字段的序号) 从1开始。
*/
while (rs.next()) {//while循环一次,代表一行
//t_employee有14个字段
for (int i = 1; i <= 14; i++) {//for循环一次,代表一行中的一个单元格
System.out.print(rs.getObject(i) + "\t");
}
System.out.println();
}
rs.close();
pst.close();
connection.close();
input.close();
}
获取自增长键值
/*
获取自增长键值:
mysql中很多表都是有自增长字段,特别是id。
当我们添加了一个员工、部门,添加成功后,需要立刻返回该员工、部门的自增长的id值。
(1)在用Connection数据库连接对象获取PreparedStatement对象时,要加一个参数
PreparedStatement pst = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
这里Statement.RETURN_GENERATED_KEYS表示,执行sql后,返回自增长键值
(2)执行完成之后,需要从PreparedStatement对象中获取自增长键值
ResultSet rs = pst.getGeneratedKeys(); //方法别调错
if(rs.next()){ //因为只有一条记录,所以只有一个自增长键值,用if即可
System.out.println("新员工编号是:" + rs.getObject(1));//因为自增长键值只有一个,所以这里直接getObject(1)即可
}
*/
//todo 获取自增的主键
@Test
public void test01() throws Exception{
//1.注册驱动
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "12345");
//3.准备sql
String sql ="insert into t_account values(null,?,?)";
//4.创建命令发送器
PreparedStatement pst = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
//5.填充数据
pst.setObject(1,"李白");
pst.setObject(2,6666);
//6.执行命令获取结果
pst.executeUpdate();
//7.获取自增的主键值
ResultSet rs = pst.getGeneratedKeys();
//8.展示主键值
while (rs.next()){
Object pid = rs.getObject(1);
System.out.println("pid = " + pid);
}
//9.关闭资源
rs.close();
pst.close();
connection.close();
}
批处理
/*
批处理:
批量执行一组sql。大多数情况下都是批量执行insert语句。
在url后面再加一个参数 rewriteBatchedStatements=true
url的格式:
jdbc:mysql://localhost:3306/atguigu
如果要加参数,需要用一个?,表示后面是参数
jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC
如果有多个参数,参数之间使用&连接,
每一个参数都是key=value的格式。
jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC&rewriteBatchedStatements=true
如何实现批处理?
(1)url中加rewriteBatchedStatements=true
jdbc:mysql://localhost:3306/atguigu?serverTimezone=UTC&rewriteBatchedStatements=true
(2)PreparedStatement对象调用
A:addBatch() //添加到批量处理
B:executeBatch() //执行批量处理
(3)不要把values写错value(学生问题)
*/
@Test
public void test02() throws Exception{
//todo 批处理
long start = System.currentTimeMillis();
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu?rewriteBatchedStatements=true", "root", "12345");
//3.准备sql
String sql = "insert into t_account values(null,?,?)";
//4.创建命令发送器
PreparedStatement pst = connection.prepareStatement(sql);
//5.填充数据
for (int i = 0; i < 10000; i++) {
pst.setObject(1,"李商隐"+i);
pst.setObject(2,i);
//6.添加到批处理
pst.addBatch();
}
//执行批处理
pst.executeBatch();
//7.关闭资源#
pst.close();
connection.close();
long end = System.currentTimeMillis();
System.out.println(end-start);// 776
}
事务处理
/*
如果多条sql要组成一个事务,要么一起成功,要么一起失败。
例如:订单
(1)修改商品表的商品库存和销量
(2)订单表新建订单数据
(3)订单明细表新建订单明细记录(多条)
....
这些sql要么一起成功,要么都还原到最初。
JDBC如何管理事务?
(1)mysql默认是自动提交事务,每执行一条语句成功后,自动提交。
需要开启手动提交模式。
Connection连接对象.setAutoCommit(false);//取消自动提交模式,开始手动提交模式
(2)sql执行成功,别忘了提交事务
Connection连接对象.commit();
(3)sql执行失败,回滚事务
Connection连接对象.rollback();
*/
//1.注册驱动
Connection connection=null;
PreparedStatement pst = null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接
connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "12345");
//todo 开启事务
connection.setAutoCommit(false);
//3.准备sql
String sql = "update t_account set balance = balance + ? where pid = ?";
//4.创建命令发送器
pst = connection.prepareStatement(sql);
//5.妲己-3000
pst.setObject(1, -3000);
pst.setObject(2, 1);
pst.executeUpdate();
// int n = 10/0;
//6.吕布+3000
pst.setObject(1, 3000);
pst.setObject(2, 2);
pst.executeUpdate();
//7.关闭资源
System.out.println("转账成功");
//todo 提交
connection.commit();
} catch (Exception e) {
System.out.println("有内鬼 终止交易");
try {
//todo 回滚
connection.rollback();
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}finally {
if(pst!=null){
try {
pst.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
数据库连接池
DataSource接口
JDBC 的数据库连接池使用 javax.sql.DataSource 来表示,DataSource 只是一个接口(通常被称为数据源),所有的Java数据库连接池都需要实现该接口。该接口通常由服务器(Weblogic, WebSphere, Tomcat)提供实现,也有一些开源组织提供实现
常见的数据库连接池
- DBCP 是Apache提供的数据库连接池,速度相对c3p0较快,但因自身存在BUG,Hibernate3已不再提供支持
- C3P0 是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以
- Proxool 是sourceforge下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点
- HikariCP 俗称光连接池,是目前速度最快的连接池
- Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于一身的数据库连接池
Druid连接池的使用
(1)加入jar包
例如:druid-1.1.10.jar
(2)代码步骤
第一步:创建druid连接池的配置文件druid.properties文件,放置到类路径下
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root 用户名
password=123456 密码
initialSize=5 初始的连接数量
maxActive=10 最大连接数
maxWait=1000 等待时间
第二步:使用工厂模式创建DruidDataSource对象
//1. 创建一个Properties对象,让其去读取druid.properties文件
Properties properties = new Properties();
//1.1 将druid.properties配置文件转成字节输入流
//FileInputStream is = new FileInputStream("D:\\讲课资料\\尚硅谷\\210323JavaEE(深圳)\\atguigu0323\\day04_JDBC_01\\resources\\druid.properties");
//使用相对路径来将配置文件转成字节输入流,我们可以使用类加载器来读取类路径下文件
//TestDataSource.class.getClassLoader() 表示获取ClassLoader对象
InputStream is = TestDataSource.class.getClassLoader().getResourceAsStream("druid.properties");
//1.2 使用properties对象加载流
properties.load(is);
//2. 使用DruidDataSourceFactory创建Druid连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
第三步:使用连接池对象获取连接
Connection connection = dataSource.getConnection();
Druid连接池的配置参数列表
配置 | 缺省 | 说明 |
---|---|---|
name | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:”DataSource-” + System.identityHashCode(this) | |
url | 连接数据库的url,不同数据库不一样。例如:mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto | |
username | 连接数据库的用户名 | |
password | 连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/使用ConfigFilter | |
driverClassName | 根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下) | |
initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive | 8 | 最大连接池数量 |
maxIdle | 8 | 已经不再使用,配置了也没效果 |
minIdle | 最小连接池数量 | |
maxWait | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 | |
poolPreparedStatements | false | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 |
maxOpenPreparedStatements | -1 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
validationQuery | 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。 | |
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis | 有两个含义: 1)Destroy线程会检测连接的间隔时间2)testWhileIdle的判断依据,详细看testWhileIdle属性的说明 | |
numTestsPerEvictionRun | 不再使用,一个DruidDataSource只支持一个EvictionRun | |
minEvictableIdleTimeMillis | ||
connectionInitSqls | 物理连接初始化的时候执行的sql | |
exceptionSorter | 根据dbType自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接 | |
filters | 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall | |
proxyFilters | 类型是List,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系 |
封装JDBCUtil
配置文件:src/jdbc.properties 或者resources/jdbc.properties
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc_test
username=root
password=123456
initialSize=5
maxActive=10
maxWait=1000
JDBCUtil工具类:
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JDBCUtil {
private static DataSource dataSource;
static {
try {
//读取配置文件,创建连接池
InputStream inputStream = JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties");
Properties properties = new Properties();
properties.load(inputStream);
//使用DruidDataSourceFactory创建连接池
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接池
* @return
*/
public static DataSource getDataSource(){
return dataSource;
}
/**
* 获取连接
* @return
*/
public static Connection getConnection(){
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
/**
* 归还连接的方法
* @param connection
*/
public static void releaseConnection(Connection connection){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
}
Apache的DBUtils
DBUtils的概述
commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。
其中QueryRunner类封装了SQL的执行,是线程安全的。
(1)可以实现增、删、改、查、
(2)考虑了事务处理需要共用Connection。
(3)该类最主要的就是简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。
DBUtils执行增删改的SQL语句
API介绍
- QueryRunner() ,创建QueryRunner对象,用于执行SQL语句
- QueryRunner的update(Connection conn, String sql, Object... params)方法,用于执行增删改的SQL语句
@Test
public void testAddUser() throws SQLException {
//目标:往user表中添加一行数据
//1. 创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
//2. 执行SQL语句
String sql = "insert into user values (null,?,?,?)";
Connection conn = JDBCUtil.getConnection();
int i = queryRunner.update(conn, sql, "aolafu", "123456", "狂战士");
//关闭连接
JDBCUtil.releaseConnection(conn);
}
@Test
public void testAddUserAnother() throws SQLException {
//1. 创建QueryRunner,并且传入连接池对象
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
//2. 执行SQL语句
String sql = "insert into user values (null,?,?,?)";
queryRunner.update(sql,"neisesi","123456","狗头");
//这种方式的缺点是用不了事务
}
@Test
public void testDeleteUser() throws SQLException {
//1. 创建QueryRunner,并且传入连接池对象
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
//2. 执行SQL语句
String sql = "delete from user where id=?";
queryRunner.update(sql,1);
}
使用QueryRunner类实现查询
API介绍
- query(String sql, ResultSetHandler
rsh, Object... params) ,执行查询 select - ResultSetHandler结果集处理类
Handler类型 | 说明 |
---|---|
ArrayHandler | 将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值 |
ArrayListHandler | 将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。 |
BeanHandler | 将结果集中第一条记录封装到一个指定的javaBean中。 |
BeanListHandler | 将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中 |
ColumnListHandler | 将结果集中指定的列的字段值,封装到一个List集合中 |
KeyedHandler | 将结果集中每一条记录封装到Map<String,Object>,在将这个map集合做为另一个Map的value,另一个Map集合的key是指定的字段的值。 |
MapHandler | 将结果集中第一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值 |
MapListHandler | 将结果集中每一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值,在将这些Map封装到List集合中。 |
ScalarHandler | 它是用于单个数据。例如select count(*) from 表。 |
@Test
public void testFindById() throws SQLException {
//使用DBUtils执行查询的SQL语句,将查询到的一条数据封装到User对象中
//1. 创建QueryRunner,并且传入连接池对象
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
//2. 执行SQL语句
String sql = "select * from user where id=?";
User user = queryRunner.query(sql, new BeanHandler<>(User.class), 2);
System.out.println(user);
}
@Test
public void testFindAll() throws SQLException {
//查询多条数据,封装到List<JavaBean>
//1. 创建QueryRunner,并且传入连接池对象
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
//2. 执行SQL语句
String sql = "select * from user";
List<User> userList = queryRunner.query(sql, new BeanListHandler<>(User.class));
System.out.println(userList);
}
@Test
public void testFindCount() throws SQLException {
//查询数据条数
//1. 创建QueryRunner,并且传入连接池对象
QueryRunner queryRunner = new QueryRunner(JDBCUtil.getDataSource());
//2. 执行SQL语句
String sql = "select count(id) from user";
long count = queryRunner.query(sql, new ScalarHandler<>());
System.out.println(count);
}
DBUtils批处理
1.创建QueryRunner对象
2.调用batch方法
3.要开启批处理
@Test
public void test01() throws Exception {
//1.创建QueryRunner对象
QueryRunner queryRunner = new QueryRunner();
//2.准备sql
String sql = "insert into users values(null,?,?,?)";
//3.数据填充
//3.110000条数据 3个位置添加数据
Object[][]objs = new Object[10000][3];
for (int i = 0; i < objs.length; i++) {
objs[i][0]="杜甫"+i;
objs[i][1]="123"+i;
objs[i][2]="dufu@atguigu.com";
}
queryRunner.batch(JDBCutils.getConnection(),sql,objs);
}
注意:类的属性名和数据库字段名相同,需要提供get/set方法
MySQL和JDBC阶段必须掌握的内容
- mysql服务器和sqlyog的安装和使用
- 会使用sqlyog对数据库、表进行创建、修改、删除
- 对于单表的数据的增删改查语句要非常熟练
- 理解多表关系,理解外键,会使用sqlyog创建和删除外键,设置外键的等级
- 难点:熟练使用内连接查询、外连接查询、子查询
- 会使用连接池+DBUtils,执行sql语句:增删改的sql语句,查询的sql语句
- 会使用JDBC执行添加的SQL语句,获取自增长的主键
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)