一、JDBC
1、JDBC的概念
Java DataBase Connectivity
JDBC是官方(sun公司)定义的一套操作所有关系型数据库的接口,厂商实现这套接口(数据库驱动jar包)。
2、API
1、注册驱动
2、获取数据库连接对象 Connection
3、定义sql
4、获取执行sql语句的对象 Statement,Pre(防止sql注入,预处理对象)
5、执行sql,接受返回结果
6、处理结果(封装到对象中等)
7、释放资源
// 底层API使用规范。学会封装 | 使用工具
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 获取连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db_temp", "root", "root");
// 定义sql语句
String sql = "update account set xx = xx where id = 1";
// 获取执行sql的对象 Statement
Statement stmt = conn.createStatement();
// 执行sql,操作影响行数
int count = stmt.executeUpdate(sql);
// 处理判断
assert count > 0;
// finally,release,must
stmt.close();
conn.close();
3、小demo
Statement stmt = null;
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
String sql = "insert into account values('王五',3000)";
conn = DriverManager.getConnection("jdbc:mysql:///db_temp", "root", "root");
stmt = conn.createStatement();
int count = stmt.executeUpdate(sql); // 返回值为:操作影响的行数
//6.处理结果
assert count > 0;
System.out.println(count);
} 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();
}
}
}
4、API说明
4.1、连接和执行对象
// DriverManager:获取数据库连接对象
// Connection:数据库连接对象,获取执行sql语句的对象,事物管理
//-------------事物控制--------------
conn.setAutoCommit(boolean autoCommit) //关闭自动事务管理
conn.commit()
conn.rollback()
//------------sql执行对象
Statement createStatement();
PreparedStatement prepareStatement(String sql); // 解决sql注入
// 执行sql的方法
boolean execute(String sql); // 可以执行任意的sql 了解
// 增删改操作
int executeUpdate(String sql); // 执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
// 查操作
ResultSet executeQuery(String sql); // 执行DQL(select)语句
4.2、获取查询结果集
// 执行sql语句,返回结果集
ResultSet // 结果集的封装
boolean next() // 结果集遍历的方法
while(rs.next()){ // 有下一行数据:返回true
int id = rs.getInt(1); // 数据和类型对应上
String name = rs.getString("name");
double balance = rs.getDouble(3);
System.out.println(id + "---" + name + "---" + balance);
}
5、解决sql注入问题
利用sql中的一些语法规则、特殊符号让服务器跳过(忽略)对某一部分数据的校验。
select * from user where name = +' + 变量 + ' + and password = +'+ 变量 +';
输入变量 = 哈哈'or 1 = 1 --
select * from user where name = '哈哈' or 1 = 1 --' + and password = +'+ 变量 +';
//----------解决方式--------------
// 使用PreparedStatement对象来解决
// 预编译的SQL:参数使用?作为占位符
// 见事务控制部分
6、结果封装
查询操作,得到到一行一行的结果集。
// 定义User类:实体类(类名、属性名和数据库名、字段名对应)
// public List<User> findAll(){}
// 实体类对象userObj
// 查询数据集合,ResultSet
// 字段遍历,赋值给实体类对象,userObj.setName(re.getString("name"))
// 实现方法 select * from user;
List<User> list = new List<User>; // 全局·集合
while(rs.next()){
User obj = new User(); // 实体类对象
// 获取数据
int id = rs.getInt(1); // index
String name = rs.getString("name"); // or fieldName
double balance = rs.getDouble(3);
// 封装数据
obj.setId(id);
obj.setName(name);
obj.setBalance(balance);
System.out.println(obj); // toString方法
// 对象放到集合中
list.append(obj);
}
// 循环结束,数据封装完成
// 遍历集合:增强for
二、冗余封装
1、封装工具类
将数据库信息封装到一个配置文件中,通过类加载器进行解析,完成数据库配置,对外提供一个返回数据库连接的方法。
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
// 静态代码块:类初始化仅仅加载一次。(静态变量、父类非静态、父类静态代码块、父类构造、子···)
static{
try {
ClassLoader classLoader = JDBCUtils.class.getClassLoader(); // 类加载器获取配置文件
// properties文件 Java文件式式数据结构
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
System.out.println(path);
// Properties集合类
Properties pro = new Properties();
pro.load(new FileReader(path));
// 获取数据,赋值
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();
}
}
// 对外提供一个方法,调用方法返回数据库连接conn
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password); // 返回:conn
}
public static void close(ResultSet rs, Statement stmt, Connection conn) {
// 资源释放,可能没有Result,但是Statement、Connection都有,可以使用方法重载(参数不同)
}
}
Connection conn = JDBCUtils.getConnection();
2、释放资源(完善)
调用工具类中的释放资源的方法(释放结果对象、sql执行对象、数据库连接对象)
// 调用使用方式
JDBCUtils.close(null, stmt, conn) // DML(增删改)操作,没有查询结果集
JDBCUtils.close(rs, stmt, conn) // 查询操作,关闭结果集、语句查询、连接
// 具体实现
public class JDBCUtils {
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();
}
}
}
}
三、事物控制
一般的都是基于同一个conn
,如果涉及到多个服务(多个数据库):查看分布式事务管理。复习MySQL事务部分。
1、说明
// 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
// 使用Connection对象来管理事务
// 开启事务:
setAutoCommit(false); // 手动
// sql语句
// 提交事务:
commit();
// 回滚事务:
rollback(); // 在catch中回滚事务
2、小案例(防止sql注入)
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);
String sql1 = "update account set balance = balance - ? where id = ?";
String sql2 = "update account set balance = balance + ? where id = ?";
pstmt1 = conn.prepareStatement(sql1);
pstmt2 = conn.prepareStatement(sql2);
pstmt1.setDouble(1, 500);
pstmt1.setInt(2, 1);
pstmt2.setDouble(1, 500);
pstmt2.setInt(2, 2);
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(null, pstmt1, conn);
}
}
}
四、数据库连接池
高效执行
1、连接池接口
// 数据库厂商实现该接口
public interface DataSource{
// 取出连接对象,厂商实现
getConnection();
// 归还对象直接调用
close();
}
2、C3P0数据库连接池
注意C3P0版本和MySQL版本,以及JDBC-url配置
// 第三方:导入2个jar包
// 定义配置文件(名字固定放到src下)
// 创建核心对象
// 获取连接getConnection();
2.1、实现配置
// 文件名字:c3p0-config.xml
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db_temp?&useSSL=false&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<!--初始化申请的连接数量-->
<property name="initialPoolSize">5</property>
<!--最大的连接数量-->
<property name="maxPoolSize">10</property>
<!--超时时间-->
<property name="checkoutTimeout">3000</property>
</default-config>
<named-config name="otherc3p0">
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db3?&useSSL=false&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">root</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
2.2、实现代码
public class C3P0Demo2 {
public static void main(String[] args) throws SQLException {
// 获取DataSource,使用默认配置
DataSource ds = new ComboPooledDataSource();
for (int i = 1; i <= 11 ; i++) {
// 获取连接
Connection conn = ds.getConnection();
System.out.println(i+":"+conn);
if(i == 5){
// 归还连接到连接池中
conn.close();
}
}
}
3、Druid数据库连接池
// 导入jar包
// 配置文件:Properties,名字任意,路径任意,手动加载
// 获取数据库连接池对象:工厂
// 获取连接getConnection();
3.1、配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.3.3:33306/Demo1
username=root
password=121388
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000
3.2、maven坐标
<!--版本搜索一波-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version></version>
</dependency>
3.3、代码
public class DruidDemo {
public static void main(String[] args) throws Exception {
//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();
System.out.println(conn);
}
}
五、JdbcTemapate
学会使用工具
1、针对连接池设计出来的
/*
* 参数:一个数据库连接池对象DataSource
* 返回值:数据库连接对象Connection
* 方法封装:基础的CRUD,有JdbcTUserlate对象调用
* 方法参数:sql语句,sql参数,封装结果集的RowMapper对象(自定义)
* 优化:自动释放资源(close)
*/
2、代码
public class JdbcTUserlateDemo1 {
public static void main(String[] args) {
// 带入jar包
// 创建JdbcTUserlate对象, 把连接池传过来
JdbcTUserlate jdbctUserlate = new JdbcTUserlate(JDBCUtils.getDataSource());
// 生成sql
String sql = "select * from fruit";
// 执行方法
Object list = (Object)jdbctUserlate.queryForList(sql);
// 自动释放资源,自动归还连接到连接池
System.out.println(list);
}
}