# JDBC
- 概念:Java DataBase Connectivity Java 数据库连接, Java 语言操作数据库
- JDBC 本质:其实是官方(sun 公司)定义的一套操作所有关系型数据库的规则,** 即接口。** 各个数据库厂商去实现这套接口,提供数据库驱动 jar 包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动 jar 包中的实现类。
- 快速入门
步骤:
- 导入驱动 jar 包 mysql-connector-java-5.1.37-bin.jar
1. 复制 mysql-connector-java-5.1.37-bin.jar 到项目的 libs 目录下
2. 右键 -->Add As Library - 注册驱动
- 获取数据库连接对象 Connection
- 定义 sql
- 获取执行 sql 语句的对象 Statement
- 执行 sql,接受返回结果
- 处理结果
- 释放资源
- 导入驱动 jar 包 mysql-connector-java-5.1.37-bin.jar
详解各个对象
# DriverManager:驱动管理对象
功能:
注册驱动:告诉程序该使用哪一个数据库驱动 jar
static void registerDriver (Driver driver) : 注册与给定的驱动程序 DriverManager 。
写代码使用: <u>Class.forName("com.mysql.jdbc.Driver");</u>
通过查看源码发现:在 com.mysql.jdbc.Driver 类中存在静态代码块
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}注意:mysql5 之后的驱动 jar 包可以省略注册驱动的步骤。
获取数据库连接:
- 方法:static Connection getConnection (String url, String user, String password)
- 参数:
- url:指定连接的路径
- 语法:jdbc:mysql://ip 地址 (域名): 端口号 / 数据库名称
- 例子:jdbc:mysql://localhost:3306/db3
- 细节:如果连接的是本机 mysql 服务器,并且 mysql 服务默认端口是 3306,则 url 可以简写为:jdbc:mysql:/// 数据库名称
- user:用户名
- password:密码
- url:指定连接的路径
# Connection:数据库连接对象
- 功能:
- 获取执行 sql 的对象
- Statement createStatement()
- PreparedStatement prepareStatement(String sql)
- 管理事务:
- 开启事务:setAutoCommit (boolean autoCommit) :调用该方法设置参数为 false,即开启事务
- 提交事务:commit ()
- 回滚事务:rollback ()
- 获取执行 sql 的对象
# Statement:执行 sql 的对象
执行 sql
- boolean execute (String sql) :可以执行任意的 sql -- 了解
- int executeUpdate (String sql) :执行 DML(insert、update、delete)语句、DDL (create,alter、drop) 语句
- 返回值:影响的行数,可以通过这个影响的行数判断 DML 语句是否执行成功 返回值 > 0 的则执行成功,反之,则失败。
- ResultSet executeQuery (String sql) :执行 DQL(select) 语句
练习:
- account 表 添加一条记录
- account 表 修改记录
- account 表 删除一条记录
代码: Statement stmt = null; Connection conn = null; try { //1. 注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2. 定义sql String sql = "insert into account values(null,'王五',3000)"; //3.获取Connection对象 conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root"); //4.获取执行sql的对象 Statement stmt = conn.createStatement(); //5.执行sql int count = stmt.executeUpdate(sql);//影响的行数 //6.处理结果 System.out.println(count); if(count > 0){ System.out.println("添加成功!"); }else{ System.out.println("添加失败!"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally { //stmt.close(); //7. 释放资源 //避免空指针异常 if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }
# ResultSet:结果集对象,封装查询结果
boolean next (): 游标向下移动一行,判断当前行是否是最后一行末尾 (是否有数据),如果是,则返回 false,如果不是则返回 true
getXxx (参数): 获取数据
- Xxx:代表数据类型 如: int getInt () , String getString ()
- 参数:
- int:代表列的编号,从 1 开始 如: getString (1)
- String:代表列名称。 如: getDouble ("balance")
注意:
使用步骤:
- 游标向下移动一行
- 判断是否有数据
- 获取数据
// 循环判断游标是否是最后一行末尾。
while(rs.next()){
// 获取数据
//6.2 获取数据
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble(3);
System.out.println(id + "---" + name + "---" + balance);
}
练习:jdbcDemo7
* 定义一个方法,查询 emp 表的数据将其封装为对象,然后装载集合,返回。
1.定义Emp类 | |
2. 定义方法 public List<Emp> findAll(){} | |
3. 实现方法 select * from emp; |
# PreparedStatement:执行 sql 的对象
SQL 注入问题:在拼接 sql 时,有一些 sql 的特殊关键字参与字符串的拼接。会造成安全性问题
输入用户随便,输入密码:a' or 'a' = 'a
sql:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'
解决 sql 注入问题:使用 PreparedStatement 对象来解决
预编译的 SQL:参数使用?作为占位符
步骤: // 重点
- 导入驱动 jar 包 mysql-connector-java-5.1.37-bin.jar
- 注册驱动
- 获取数据库连接对象 Connection
- 定义 sql
- 注意:sql 的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
- 获取执行 sql 语句的对象 PreparedStatement Connection.prepareStatement (String sql)
- 给?赋值:
- 方法: setXxx (参数 1, 参数 2)
- 参数 1:?的位置编号 从 1 开始
- 参数 2:?的值
- 方法: setXxx (参数 1, 参数 2)
- 执行 sql,接受返回结果,不需要传递 sql 语句
- 处理结果
- 释放资源
注意:后期都会使用 PreparedStatement 来完成增删改查的所有操作
可以防止 SQL 注入
效率更高
# 抽取 JDBC 工具类 : JDBCUtils
目的:简化书写 jdbcUtils + jdbcDemo7 + jdbc.properties 实现练习
分析:1 注册驱动也抽取,2 抽取一个方法获取连接对象
需求:不想传递参数(麻烦),还得保证工具类的通用性。
解决:配置文件 jdbc.properties
url= | |
user= | |
password= | |
driver= |
# JDBC 控制事务
事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
操作:1 开启事务 2 提交事务 3 回滚事务
使用 Connection 对象来管理事务
- 开启事务:setAutoCommit (boolean autoCommit) :调用该方法设置参数为 false,即开启事务
- 在执行 sql 之前开启事务
- 提交事务:commit ()
- 当所有 sql 都执行完提交事务
- 回滚事务:rollback ()
- 在 catch 中回滚事务
public class JDBCDemo10 { | |
public static void main(String[] args) { | |
Connection conn = null; | |
PreparedStatement pstmt1 = null; | |
PreparedStatement pstmt2 = null; | |
try { | |
//1. 获取连接 | |
conn = JDBCUtils.getConnection(); | |
// 开启事务 | |
conn.setAutoCommit(false); | |
//2. 定义 sql | |
//2.1 张三 - 500 | |
String sql1 = "update account set balance = balance - ? where id = ?"; | |
//2.2 李四 + 500 | |
String sql2 = "update account set balance = balance + ? where id = ?"; | |
//3. 获取执行 sql 对象 | |
pstmt1 = conn.prepareStatement(sql1); | |
pstmt2 = conn.prepareStatement(sql2); | |
//4. 设置参数 | |
pstmt1.setDouble(1,500); | |
pstmt1.setInt(2,1); | |
pstmt2.setDouble(1,500); | |
pstmt2.setInt(2,2); | |
//5. 执行 sql | |
pstmt1.executeUpdate(); | |
// 手动制造异常 | |
int i = 3/0; | |
pstmt2.executeUpdate(); | |
// 提交事务 | |
conn.commit(); | |
} catch (Exception e) { | |
// 事务回滚 | |
try { | |
if(conn != null) { | |
conn.rollback(); | |
} | |
} catch (SQLException e1) { | |
e1.printStackTrace(); | |
} | |
e.printStackTrace(); | |
}finally { | |
JDBCUtils.close(pstmt1,conn); | |
JDBCUtils.close(pstmt2,null); | |
} | |
} |
# 数据库连接池
概念:其实就是一个容器 (集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。好处: 节约资源 用户访问高效
实现:
- 标准接口:DataSource Javax.sql 包下的
- 方法:
- 获取连接:getConnection ()
- 归还连接:Connectionless ()。如果连接对象 Connection 是从连接池中获取的,那么调用 Connection.close () 方法,则不会再关闭连接了。而是归还连接
- 方法:
- 一般我们不去实现它,有数据库厂商来实现
- C3p0:数据库连接池技术
- Druid:数据库连接池实现技术,由阿里巴巴提供
- 标准接口:DataSource Javax.sql 包下的
# C3p0:数据库连接池技术
步骤:
导入 jar 包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar
不要忘记导入数据库驱动 jar 包
定义配置文件:
名称: c3p0.properties 或者 c3p0-config.xml
路径:直接将文件放在 src 目录下即可。
创建核心对象 数据库连接池对象 ComboPooledDataSource
获取连接: getConnection
代码:
创建数据库连接池对象
DataSource ds = new ComboPooledDataSource();
获取连接对象
Connection conn = ds.getConnection ();
# Druid:数据库连接池
# 步骤
1 导入 jar 包 druid-1.0.9.jar
2 定义配置文件:
- 是 properties 形式的
- 可以叫任意名称,可以放在任意目录下
3 加载配置文件。Properties
4 获取数据库连接池对象:通过工厂类来获取 DruidDataSourceFactory
5 获取连接:getConnection
1 导入jar包
2 导入配置文件
3 加载配置文件
Properties pro = new Properties();
InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
4 获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
5 获取连接
Connection conn = ds.getConnection();
# 定义工具类
- 定义一个类 JDBCUtils
- 提供静态代码块加载配置文件,初始化连接池对象
- 提供方法
- 获取连接方法:通过数据库连接池获取连接
- 释放资源
- 获取连接池的方法
# Spring JDBC
Spring 框架对 JDBC 的简单封装。提供了一个 JDBCTemplate 对象简化 JDBC 的开发
步骤:
导入 jar 包
创建 JdbcTemplate 对象。依赖于数据源 DataSource
JdbcTemplate template = new JdbcTemplate(ds);
3. 调用 JdbcTemplate 的方法来完成 CRUD 的操作
update (): 执行 DML 语句。增、删、改语句
4.queryForMap (): 查询结果将结果集封装为 map 集合,将列名作为 key,将值作为 value 将这条记录封装为一个 map 集合
注意:这个方法查询的结果集长度只能是 1queryForList (): 查询结果将结果集封装为 list 集合
注意:将每一条记录封装为一个 Map 集合,再将 Map 集合装载到 List 集合中query (): 查询结果,将结果封装为 JavaBean 对象
uery 的参数:RowMapper
一般我们使用 BeanPropertyRowMapper 实现类。可以完成数据到 JavaBean 的自动封装
new BeanPropertyRowMapper <类型>(类型.class)queryForObject:查询结果,将结果封装为对象
般用于聚合函数的查询
public void test6_2(){ | |
String sql = "select * from emp"; | |
List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class)); | |
for (Emp emp : list) { | |
System.out.println(emp); | |
} | |
} |