JDBC
穷且益坚 不坠青云之志
文章目录
一、概念
1. 简介
- JDBC:Java DataBase Connectivity,java语言操作数据库
- JDBC本质:官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行代码时驱动jar包中的实现类
二、入门
1. 步骤
- 1)导入jar包
- 复制驱动到项目的libs目录下
- 右键–Add As Library
- 2)注册驱动
- 3)获取数据库连接对象 Connection
- 4)定义sql语句
- 5)获取执行sql语句的对象 Statement
- 6)执行sql,接收返回结果
- 7)处理结果
- 8)释放资源
2. 代码
//1.导入jar包
//2.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//3.获取数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/girls?serverTimezone = GMT", "root", "root");
//4.定义sql语句
String sql = "update admin set password = 7777 where id = 2";
//5.获取执行sql的对象
Statement statement = conn.createStatement();
//6.执行sql
int count = statement.executeUpdate(sql);
//7.处理结果
System.out.println(count);
//8.释放资源
statement.close();
conn.close();
三、详解
1. 各个对象
- 1)DriverManager:驱动管理对象
- 2)Connection:数据库连接对象
- 3)Statement:执行sql的对象
- 4)ResultSet:结果集对象
- 5)PreparedStatement:
2. 详解
2.1 DriverManager
① 功能:
-
1)注册驱动:告诉程序应该使用哪个数据库驱动jar
-
方法:
static void registerDriver(Driver driver)
,注册给定的程序驱动 -
而写代码时却用的时:
Class.forName("com.mysql.cj.jdbc.Driver");
这是为什么呢? -
通过查看源码发现:在com.mysql.cj.jdbc.Driver类中存在静态代码块
-
static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }
-
静态代码块在加载进内存时自动执行
-
-
2)获取数据库连接
- 方法:
static Connection getConnection(...)
- url:指定连接的路径:
jdbc:mysql://ip地址:端口/数据库名称
- 在最新驱动中还需要添加:
?serverTimezone = GMT
- user:用户名
- password:密码
- url:指定连接的路径:
- 方法:
2.2 Connection
① 功能
- 1)获取执行sql的对象
Statement createStatement(String sql)
PreparedStatement prepareStatement(String sql)
- 2)管理事物
- 开启事物:
void setAutoCommit(boolean autoCommit)
:调用该方法设置参数为false,即开启事物 - 提交事物:
commit()
- 回滚事物:
rollback()
- 开启事物:
2.3 Statement
① 功能
- 1)执行sql
boolean execute(String sql)
:可以执行任意的sql语句(了解)int executeUpdate(String sql)
:执行DML、DDL语句- 返回值:影响的行数。可以通过影响的函数可以判断DML语句是否执行成功(>0)
ResultSet executeQuery(String sql)
:执行DQL语句
2.4 ResultSet
① 功能:封装结果集对象
boolean next()
:游标下移一行getXxx(参数)
:获取数据- Xxx:Int、String…
- 参数:
- int:代表列的编号(从1开始)。如:
getInt(1)
- String:代表列的名称。如:
getString("password")
- int:代表列的编号(从1开始)。如:
② 正确使用
while (rs.next()) {
String name = rs.getString(2);
System.out.println(name);
}
2.5 PreparedStatement
① 简介
- 1)SQL注入:在拼接sql时,有一些sql的特殊关键字参与字符串拼接,造成安全问题
- 2)PreparedStatement:预编译的SQL:参数使用
?
作为占位符 - 3)PreparedStatement可以防止SQL注入
- 4)PreparedStatement 是 Statement 的子类
② 使用步骤
- 1)SQL语句:
String sql = select * from where id = ?
- 2)获取对象:
PerparedStatement = conn.prepareStatement(sql)
- 3)设置参数:
setXxx(参数1, 参数2)
- 参数1:?的位置编号(从1开始)
- 参数2:?的值
- 4)执行SQL:与Statement的使用方式一样(不需要在传递sql)
四、JDBCUtils
1. 分析
- 封装注册驱动
- 封装获取连接对象
- 封装释放资源
2. 代码
/**
* JDBC工具类
*/
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
//读取配置文件
static {
try {
Properties pro = new Properties();
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc.properties");
pro.load(is);
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//获取连接对象
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
//释放资源
public static void close(Statement stmt, Connection conn){
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//释放资源
public static void close(ResultSet rs, Statement stmt, Connection conn){
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
五、事物
1. 简介
- 1)事物:一个包含多个步骤业务的操作。如果这个步骤被事物管理,则这个步骤要么同时成功,要么同时失败
- 2)操作:
- 开启事物:
void setAutoCommit(boolean autoCommit)
- 提交事物:
commit()
- 回滚事物:
rollback()
- 开启事物:
- 3)使用Connection对象管理事物
- 4)使用场景:在代码出现异常时,需要使执行完毕的代码回到未执行时。
2. 使用
try{
conn = JDBCUtils.getConnection();
//设置开启事物
conn.setAutoCommit(false);
//...代码
//最后提交事物
conn.commit();
}catch(Exeception e){
//如果在代码执行过程中出现异常,应回滚事物
try{
if(conn != null){
conn.rollback();
}
}catch(SQLExeception e1){
e1.printStackTrace();
}
}finally{
//关闭资源
}
六、连接池
1. 简介
① 概念
- 连接池就是一个容器(集合),存放数据库连接的容器
- 当系统初始化后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取对象。用户访问完之后,会将连接对象归还给容器
- 好处:节约系统资源、高效
② 实现
- 标准接口:DataSource(javax.sql)
- 获取连接:getConnection()
- 归还连接:Connection.close()
- 一般我们不去实现它,由数据库厂商来实现
- C3P0:数据库连接池技术
- Druid:数据库连接池技术(阿里巴巴提供)
2. C3P0
① 步骤
- 1)导入jar包:
- c3p0.far
- mchange-commins-java.far
- mysql驱动jar包
- 2)定义配置文件:
- 名称:c3p0.properties 或者 c3p0-config.xml
- 路径:将文件放在src目录下
- 3)创建数据库连接池对象:ComboPooledDataSource
- 4)获取连接:getConnection
② 代码
//1.创建数据库连接对象
DataSource ds = new ComboPooledDataSource();
//2.获取连接对象
Connection conn = ds.getConnection();
3. Druid
① 步骤
- 1)导入jar包:druid-1.0.9.jar
- 2)定义配置文件:
- 是properties形式文件
- 可以叫任意名称,可以放在任意目录下
- 3)加载配置文件
- 4)获取数据库连接池对象:通过工厂类获取:
DruidDataSourceFactory.createDataSource(pro)
- 5)获取连接:getConnection()
② 定义工具类
- 定义类
- 提供静态代码块,加载配置文件,初始化连接池对象
- 提供方法:
- 获取连接方法:通过数据库连接池获取连接
- 释放资源
- 获取连接池的方法
③ 代码
@Test
public void testDruid() throws Exception {
//1.导入jar包
//2.定义配置文件
//3.加载配置文件
Properties properties = new Properties();
InputStream is = Test01_Druid.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(is);
//4.获取连接池对象
//在spring中发现,由spring创建的是DruidDataSource对象,故,DataSource是接口。
//DruidDataSource的父类集成了DataSource接口
DataSource ds = DruidDataSourceFactory.createDataSource(properties);
//5.获取连接
Connection connection = ds.getConnection();
System.out.println(connection);
}
七、Spring JDBC:Template
1. 简介
- Spring框架对JDBC的简单封装。提供类一个JDBCTemplate对象简化JDBC的开发
- 使用Template时需要使用数据库连接池技术
2. 步骤
- 1)导入jar包(5个)
- 2)创建JDBCTemplate对象。依赖与数据源DataSource
- 如:
JdbcTemplate template = new JdbcTemplate(ds)
- 如:
- 3)调用JDBCTemplate的方法来完成CRUD的操作
- update():执行DML语句(增删改)。
- queryForMap():查询结果,并封装为map集合:返回结果只能是一个
- quertForList():
- query():查询结果,封装为JavaBean
- 参数1:sql语句
- 参数2:
new BeanPropertyRowMapper<Admin>(Admin.class)
- queryForObject:查询结果,封装为对象
八、读写Blob数据
1. 简介
① blob类型
- tinyBlob:255
- blob:65k
- mediumBlob:16m
- longBlob:4g
② 报错:too large
- 在mysql安装目录下,my.ini文件添加
max_allow_package=16M
,并重启服务
2. 实现
① DML
/**
* 插入和修改操作一样
* 需要先读取文件流
* @throws Exception
*/
@Test
public void testInsert() throws Exception {
//1.获取连接
Connection conn = JDBCUtils.getConnection();
//2.创建sql语句
String sql = "update beauty set photo = ? where id = ?";
//3.创建执行sql对象
PreparedStatement ps = conn.prepareStatement(sql);
//4.获取文件流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("9.jpg")));
//5.设置参数
ps.setBlob(1, bis);
ps.setInt(2,1);
ps.executeUpdate();
JDBCUtils.close(ps, conn);
}
② DQL
@Test
public void testRead() throws Exception {
Connection conn = JDBCUtils.getConnection();
String sql = "select photo from beauty where id = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, 1);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
// Blob blob = rs.getBlob(1);
//将blob类型的字段下载下来,以文件的方式保存本地
Blob photo = rs.getBlob("photo");
InputStream is = photo.getBinaryStream();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("09_query.jpg")));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.flush();
}
JDBCUtils.close(rs, ps, conn);
}
getBlob(1);
//将blob类型的字段下载下来,以文件的方式保存本地
Blob photo = rs.getBlob(“photo”);
InputStream is = photo.getBinaryStream();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("09_query.jpg")));
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.flush();
}
JDBCUtils.close(rs, ps, conn);
}