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 |
DriverManager用于管理JDBC驱动,它有两个功能
jdbc:mysql://IP地址:端口号/数据库名
jdbc:mysql:///数据库名
// 将要分析的源码(在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!"); } }
常用方法 | 返回值 | 说明 |
---|---|---|
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都代表一个物理连接会话,要想访问数据库,必须先获得数据库连接
获取执行SQL的对象
管理事务
常用方法 | 返回值 | 说明 |
---|---|---|
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用于执行静态SQL语句并返回其生成的结果对象.该对象既可以执行DML语句,也可以执行DDL/DCL语句,还可用于执行SQL查询
常用方法 | 返回值 | 说明 |
---|---|---|
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执行的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,可以通过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可以通过列索引或列名获得列数据.它包含了多个常用方法来移动记录指针
常用方法 | 返回值 | 说明 |
---|---|---|
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(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等)
DataSource通常被称为数据源,它包含连接池和连接池管理两部分.DataSource用来取代DriverManager来获取Connection,获取速度快,同时可以大幅度提高数据库卡访问速度
使用步骤:
ComboPooledDataSource
<?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>
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需要的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所需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);