MySQL类型和Java类型相互转换
SQL类型 | Java类型 |
---|---|
tinyint | byte |
smallint | short |
int | integer |
bigint | long |
char/varchar/longvarchar | String |
DATE | java.sql.Date |
TIME | java.sql.Time |
TIMESTAMP | java.sql.Timestamp |
JDBC相关对象
DriverManager驱动管理
DriverManager用于管理JDBC驱动,它有两个功能
- 注册驱动:告诉程序该使用哪一个数据库驱动JAR
- 获取数据库连接
- URL指定连接的路径
jdbc:mysql://IP地址:端口号/数据库名
- 如果连接的是本地MySQL服务器,并且默认端口是3306,则URL可以简写
jdbc:mysql:///数据库名
- URL指定连接的路径
// 将要分析的源码(在MySQL驱动5以后,源码META-INF/services/java.sql.Driver中增添了驱动地址,所以一下这行代码可省略)
Class.forName("com.mysql.cj.jdbc.Driver");
// 通过源码发现,在com.mysql.cj.jdbc.Driver类中存在静态代码块
static {
try {
DriverManager.registerDriver(new Driver()); // 加载驱动类到内存的这行代码可省略
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
DriverManager常用方法
常用方法 | 返回值 | 说明 |
---|---|---|
getConnection(String url) | static Connection | 获取参数URL对应的数据库的链接 |
getConnection(String url, Properties info) | static Connection | 获取参数对应的数据库的链接 |
getConnection(String url, String user, String password) | static Connection | 获取参数对应的数据库的链接 |
getDriver(String url) | static Driver | 获取给定参数URL的驱动程序 |
getDrivers() | static Enumeration | 获取所有调用者可以访问的所有当前加载的JDBC驱动程序检索枚举 |
getLoginTimeout() | static int | 获取尝试登录数据库时驱动程序可以等待的最长时间(秒) |
setLoginTimeout(int seconds) | static void | 设置驱动程序在识别驱动程序后尝试连接到数据库时等待的最长时间(秒) |
getLogWriter() | static PrintWriter | 检索日志记录器 |
setLogWriter(PrintWriter out) | static void | 设置 DriverManager和所有驱动程序使用的记录/跟踪 PrintWriter对象 |
deregisterDriver(Driver driver) | static void | 从 DriverManager的注册驱动程序列表中删除指定的驱动程序 |
registerDriver(Driver driver) | static void | 注册与给定的驱动程序 DriverManager |
registerDriver(Driver driver, DriverAction da) | static void | 注册与给定的驱动程序 DriverManager |
println(String message) | static void | 打印到当前JDBC日志流的消息 |
Connection连接对象
Connection代表数据库连接对象,每个Connection都代表一个物理连接会话,要想访问数据库,必须先获得数据库连接
-
获取执行SQL的对象
- 获取Statement对象
- 获取PreparedStatement对象
- 获取CallableStatement对象,该对象用于调用存储过程
-
管理事务
- 开启事务:setAutoCommit(boolean autoCommit),调用该方法时设置参数为false即可,就能开启事务
- 提交事务:commit()
- 回滚事务:rollback()
Connection常用方法
常用方法 | 返回值 | 说明 |
---|---|---|
createStatement() | Statement | 返回一个Statement对象 |
createStatement(int resultSetType, int resultSetConcurrency) | Statement | 返回一个Statement对象 |
createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) | Statement | 返回一个Statement对象 |
prepareStatement(String sql) | PreparedStatement | 返回一个PreparedStatement对象 |
prepareStatement(String sql, int autoGeneratedKeys) | PreparedStatement | 返回一个PreparedStatement对象 |
prepareStatement(String sql, int[] columnIndexes) | PreparedStatement | 返回一个PreparedStatement对象 |
prepareStatement(String sql, int resultSetType, int resultSetConcurrency) | PreparedStatement | 返回一个PreparedStatement对象 |
prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) | PreparedStatement | 返回一个PreparedStatement对象 |
prepareStatement(String sql, String[] columnNames) | PreparedStatement | 返回一个PreparedStatement对象 |
prepareCall(String sql) | CallableStatement | 返回一个CallableStatement对象 |
prepareCall(String sql, int resultSetType, int resultSetConcurrency) | CallableStatement | 返回一个CallableStatement对象 |
prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) | CallableStatement | 返回一个CallableStatement对象 |
setAutoCommit(boolean autoCommit) | void | 设置为false,则会关闭自动提交,打开事务 |
getAutoCommit() | boolean | 检索此Connection对象的当前自动提交模式 |
commit() | void | 提交事务 |
rollback() | void | 回滚事务 |
rollback(Savepoint savepoint) | void | 将事物回滚到指定的保存点 |
setTransactionIsolation(int level) | void | 设置事务的隔离级别 |
getTransactionIsolation() | int | 获取此Connection对象的当前事务隔离级别 |
setSavepoint() | Savepoint | 创建一个保存点 |
setSavepoint(String name) | Savepoint | 以指定名字来创建一个保存点 |
releaseSavepoint(Savepoint savepoint) | void | 删除/释放保存点 |
close() | void | 关闭资源 |
abort(Executor executor) | void | 终止打开的连接 |
getNetworkTimeout() | int | 获取数据库连接的超时时间 |
setNetworkTimeout(Executor executor, int milliseconds) | void | 设置数据库连接的超时时间 |
getSchema() | String | 获取该Connection访问的数据库Schema |
setSchema(String schema) | void | 设置要访问的给定模式名称 |
getMetaData() | DatabaseMetaData | 获取元数据 |
isClosed() | boolean | 检索此Connection对象是否已关闭 |
isReadOnly() | boolean | 检索此Connection对象是否处于只读模式 |
setReadOnly(boolean readOnly) | void | 将此连接设置为只读模式,作为驱动程序的提示以启用数据库优化 |
isValid(int timeout) | boolean | 如果连接尚未关闭并且仍然有效,则返回true |
Statement
Statement用于执行静态SQL语句并返回其生成的结果对象.该对象既可以执行DML语句,也可以执行DDL/DCL语句,还可用于执行SQL查询
Statement常用方法
常用方法 | 返回值 | 说明 |
---|---|---|
executeQuery(String sql) | ResultSet | 执行给定的SQL语句,该语句返回单个ResultSet对象 |
executeUpdate(String sql) | int | 执行给定的SQL语句,这可能是INSERT/UPDATE/DELETE语句,或者不返回任何内容,如SQL DDL语句的SQL语句 |
executeUpdate(String sql, int autoGeneratedKeys) | int | 执行给定的SQL语句 |
executeUpdate(String sql, int[] columnIndexes) | int | 执行给定的SQL语句 |
executeUpdate(String sql, String[] columnNames) | int | 执行给定的SQL语句 |
execute(String sql) | boolean | 执行给定的SQL语句,这可能会返回多个结果 |
execute(String sql, int autoGeneratedKeys) | boolean | 执行给定的SQL语句 |
execute(String sql, int[] columnIndexes) | boolean | 执行给定的SQL语句 |
execute(String sql, String[] columnNames) | boolean | 执行给定的SQL语句 |
executeBatch() | int[] | 将一批命令提交到数据库以执行,并且所有命令都执行成功,返回一个更新计数的数组 |
executeLargeBatch() | default long[] | 将一批命令提交到数据库以执行,并且所有命令都执行成功,返回一个更新计数的数组 |
executeLargeUpdate(String sql) | default long | 执行给定的SQL语句 |
executeLargeUpdate(String sql, int autoGeneratedKeys) | default long | 执行给定的SQL语句 |
executeLargeUpdate(String sql, int[] columnIndexes) | default long | 执行给定的SQL语句 |
executeLargeUpdate(String sql, String[] columnNames) | default long | 执行给定的SQL语句 |
close() | void | 关闭资源 |
closeOnCompletion() | void | 当所有依赖于该Statement的Result关闭时,该Statement会自动关闭 |
cancel() | void | 如果DBMS和驱动程序都支持中止SQL语句,则取消此 Statement对象 |
isClosed() | boolean | 判断是否关闭 |
isCloseOnCompletion() | boolean | |
addBatch(String sql) | void | 添加批处理 |
clearBatch() | void | 清除批处理 |
getConnection() | Connection | 获取Connection对象 |
getResultSet() | ResultSet | 获取ResultSet对象 |
代码案例:增删改
Class.forName("com.mysql.cj.jdbc.Driver");
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
Statement stmt = conn.createStatement();
) {
String sql = "insert into user values(null,'张三','男','2022-02-01')";
int rows = stmt.executeUpdate(sql);
System.out.println(rows > 0 ? "成功" : "失败");
} catch (Exception e) {
e.printStackTrace();
}
代码案例:查询
Class.forName("com.mysql.cj.jdbc.Driver");
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
Statement stmt = conn.createStatement();
) {
String sql = "select * from user";
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt(1);
String name = rs.getString(2);
String gender = rs.getString(3);
Date birthDay = rs.getDate(4);
System.out.println(id + "\t" + name + "\t" + gender + "\t" + birthDay);
}
} catch (Exception e) {
e.printStackTrace();
}
PreparedStatement
PreparedStatement执行的SQL语句中的参数用问号来表示,调用PreparedStatement对象的setXXX(int index,XXX value)方法来设置这些参数.setXXX()方法有两个参数,第一个参数是要设置SQL语句中的参数索引(从1开始),第二个参数是设置的SQL语句中的参数值
- 调用
executeQuery()
: 返回ResultSet对象 - 调用
executeUpdate()
: 执行增删改操作
注意:execute()/executeQuery()/executeUpdate() 三个方法执行SQL语句,都不需要传递参数,因为PreparedStatement已存储了预编译的SQL语句
Class.forName("com.mysql.cj.jdbc.Driver");
String sql = "update user set name = ? where id = 1";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
PreparedStatement pstmt = conn.prepareStatement(sql);
) {
pstmt.setString(1, "zhangsan");
int rows = pstmt.executeUpdate();
System.out.println(rows > 0 ? "成功" : "失败");
} catch (Exception e) {
e.printStackTrace();
}
CallableStatement
调用存储过程使用CallableStatement,可以通过Connection的prepareCall()方法来创建CallableStatement对象,创建该对象时需要传入调用存储过程的SQL语句.调用存储过程的SQL语句总是这种形式: {call 存储过程名(?,?,?)}
,其中的问号作为存储过程参数的占位符
create procedure add_pro(a int, b int, out sum int)
begin
set sum = a + b;
end;
代码案例:存储过程
Class.forName("com.mysql.cj.jdbc.Driver");
String sql = "{call add_pro(?,?,?)}";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
CallableStatement cstmt = conn.prepareCall(sql);
) {
cstmt.setInt(1, 4);
cstmt.setInt(2, 5);
cstmt.registerOutParameter(3, Types.INTEGER); // 注册第三个参数是int类型
cstmt.execute(); // 执行存储过程
String sum = cstmt.getString(3); // 获取存储过程传出的参数值
System.out.println(sum);
} catch (Exception e) {
e.printStackTrace();
}
ResultSet结果集对象
ResultSet结果集对象,该对象包含访问查询结果的方法,ResultSet可以通过列索引或列名获得列数据.它包含了多个常用方法来移动记录指针
ResultSet常用方法
常用方法 | 返回值 | 说明 |
---|---|---|
close() | void | 释放ResultSet对象 |
absolute(int row) | boolean | 将结果集的记录指针移动到第row行;如果row为负数,则移动到倒数第row行;如果移动后的记录指针指向一条有效记录,则方法返回true |
beforeFirst() | void | 将ResultSet的记录指针定位到首行之前;这是ResultSet结果集记录指针的初始状态 |
afterLast() | void | 将ResultSet的记录指针定位到最后一行之后 |
first() | boolean | 将ResultSet的记录指针定位到首行;如果移动后的记录指针指向一条有效记录,则方法返回true |
last() | boolean | 将ResultSet的记录指针定位到最后一行;如果移动后的记录指针指向一条有效记录,则方法返回true |
previous() | boolean | 将ResultSet的记录指针定位到上一行;如果移动后的记录指针指向一条有效记录,则方法返回true |
next() | boolean | 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据);如果是,则返回false,如果不是则返回true |
getXXX(int columnIndex) | int | 参数int代表列的编号,从1开始 |
getXXX(String columnLabel) | String | 参数int代表列的名称 |
处理Blob类型数据
Blob(Binary Long Object)是二进制长对象的意思,Blob常用语存储大文件,典型的Blob内容是一张图片或一个声音文件,由于它们的特殊性,必须使用特殊的方式来存储.使用Blob可以把图片声音等文件的二进制数据保存在数据库里,并可以从数据库里恢复指定文件
如果需要将图片插入数据库,显然不能直接通过普通的SQL语句来完成,因为有一个关键的问题——Blob常量无法表示,所以需要使用PreparedStatement把Blob数据插入数据库(因为Blob数据时无法使用字符串拼写的),该对象有一个setBinaryStream(int parameterIndex,InputStream x)方法为指定参数传入二进制输入流,从而可以实现将Blob数据保存到数据库;当需要从ResultSet中取出Blob数据时,可以调用ResultSet的getBlob(int columnIndex)方法,该方法将返回一个Blob对象,Blob对象提供了getBinaryStream()方法来获取该Blob数据的输入流,也可以使用Blob对象提供的getBytes()方法直接取出该Blob对象封装的二进制数据
如果在指定了相关的Blob类型以后,还报错"XXX too large",那么在MySQL的安装目录下,找my.ini文件加上如下的配置参数即可 max_allowed_packet=16M
.同时在修改了my.ini文件之后,需要重启MySQL服务
MySQL中四种Blob类型 | 大小/字节 |
---|---|
TinyBlob | 最大 255 |
Blob | 最大 64K |
MediumBlob | 最大 16M |
LongBlob | 最大 4G |
注意 : 如果存储的文件过大,数据库的性能会下降
代码案例:插入数据
Class.forName("com.mysql.cj.jdbc.Driver");
String sql = "insert into user values (null,?,?,?,?)";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
PreparedStatement pstmt = conn.prepareStatement(sql);
) {
pstmt.setObject(1, "zhangsan");
pstmt.setObject(2, "女");
pstmt.setObject(3, "2022-01-01");
FileInputStream fis = new FileInputStream(new File("C:\\Users\\zhang\\Desktop\\avatar.jpg"));
pstmt.setBlob(4, fis);
pstmt.execute();
} catch (Exception e) {
e.printStackTrace();
}
代码案例:读取数据
Class.forName("com.mysql.cj.jdbc.Driver");
String sql = "select photo from user where name = ?";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
PreparedStatement pstmt = conn.prepareStatement(sql);
) {
pstmt.setObject(1, "zhangsan");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
Blob photo = rs.getBlob("photo");
InputStream input = photo.getBinaryStream();
FileOutputStream fos = new FileOutputStream("photo.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
}
} catch (Exception e) {
e.printStackTrace();
}
代码案例:批处理
Class.forName("com.mysql.cj.jdbc.Driver");
String sql = "insert into user(name,gender,birthday) values(?,?,?)";
try (Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "123456");
PreparedStatement pstmt = conn.prepareStatement(sql);
) {
for (int i = 0; i < 100; i++) {
pstmt.setObject(1, "name_" + i);
pstmt.setObject(2, "男");
pstmt.setObject(3, "2022-01-01");
pstmt.addBatch(); // 添加批处理
pstmt.executeBatch(); // 执行批处理
pstmt.clearBatch(); // 清空批处理
}
} catch (Exception e) {
e.printStackTrace();
}
数据库连接池
JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由商用服务器(如WebLogic,WebSphere)等提供实现,也有一些开源组织提供实现(如C3P0和DBCP等)
- C3P0 : 是一个开源组件提供的一个数据库连接池,速度相对较慢,稳定性还可以,Hibernate官方推荐使用
- DBCP : 是Apache提供的数据库连接池,Tomcat服务器自带DBCP连接池,速度相对C3P0较快,但因自身存在BUG,Hibernate3已不再提供支持
- Druid : 是阿里提供的数据库连接池,据说是集C3P0/DBCP优点于一身的数据库连接池
DataSource通常被称为数据源,它包含连接池和连接池管理两部分.DataSource用来取代DriverManager来获取Connection,获取速度快,同时可以大幅度提高数据库卡访问速度
C3P0
使用步骤:
- 导入JAR包
- c3p0-0.9.5.5.jar
- mchange-commons-java-0.2.19.jar
- mysql-connector-java-8.0.27.jar
- 定义配置文件
- 名称 : c3p0-config.xml 或者 c3p0.properties
- 位置 : 直接将文件放在src目录下即可
- 创建数据库连接对象
ComboPooledDataSource
- 获取连接
配置文件:c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!--默认配置-->
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/test</property>
<property name="user">root</property>
<property name="password">123456</property>
<!--当数据库连接池中的连接数不够时,C3P0一次向数据库服务器申请的连接数-->
<property name="acquireIncrement">5</property>
<!--C3P0数据库连接池中初始化时的连接数-->
<property name="initialPoolSize">5</property>
<!--C3P0数据库连接池维护的最大连接数-->
<property name="maxPoolSize">10</property>
<!--C3P0数据库连接池超时时间-->
<property name="checkoutTimeout">3000</property>
</default-config>
<!--配置连接池mysql-->
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/CoupleSpace</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</named-config>
</c3p0-config>
代码案例:C3P0
DataSource dataSource = new ComboPooledDataSource();
for (int i = 0; i < 10; i++) {
Connection conn = dataSource.getConnection();
System.out.println(i + " : " + conn);
if(i == 5){
conn.close();
}
}
DBCP
DBCP需要的JAR包
- commons-dbcp2-2.9.0.jar
- commons-pool2-2.10.0.jar
- commons-logging-1.2.jar
创建 dbcp.properties
文件
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=123456
Properties prop = new Properties();
InputStream input = ClassLoader.getSystemClassLoader().getResourceAsStream("dbcp.properties");
prop.load(input);
DataSource dataSource = BasicDataSourceFactory.createDataSource(prop);
Connection conn = dataSource.getConnection();
System.out.println(conn);
Druid
Druid所需JAR包
- druid-1.2.8.jar
- javax.annotation-api-1.3.2.jar
创建 druid.properties
文件;文件名可以是任意的,也可以放在任意目录下
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000
Properties prop = new Properties();
InputStream input = Main.class.getClassLoader().getResourceAsStream("druid.properties");
prop.load(input);
DataSource dataSource = BasicDataSourceFactory.createDataSource(prop);
Connection conn = dataSource.getConnection();
System.out.println(conn);