回顾
Jdbc 的使用步骤
- 导入 jar 包
- 注册驱动 Class.forName(“com.mysql.jdbc.Driver”)
- 创建连接对象 Connection conn = DriverManager.getConnection(“连接字符串”,“用户名”,“密码”)
- jdbc:mysql://ip地址:3306/数据库名
- PreparedStatement stmt = conn.prepareStatement(“sql”)
- 执行sql
- executeUpdate() 执行增删改,返回值代表影响行数
- executeQuery() 执行查询,返回 ResultSet 代表结果
- 释放资源
- rs.close
- stmt.close
- conn.close
PreparedStatement 如何使用,它可以解决什么样的问题
- PreparedStatement stmt = conn.prepareStatement(“select * from 表 where id=?”)
- PreparedStatement stmt = conn.prepareStatement(“insert into 表 values(?,?,?)”)
- ? 占位符只能代替值,不能代替关键字、表名、列名
- stmt.setXXX(?的索引, 值); // 注意索引从1开始
ResultSet 如何使用
- ResultSet rs = …
- while(rs.next() )
- rs.getXXX(“列名”)
Jdbc 工具类会用
- Jdbc.getConnection() 获取数据库连接
- Jdbc.close(rs, stmt, conn) 关闭资源
今日内容
1. jdbc 事务(会用)
- conn.setAutoCommit(false) 不让自动提交,相当于事务由程序员自己控制
- conn.commit()
- conn.rollback()
结论
- 将来事务的控制要放在 service 来执行
- 控制事务要保证 connection 对象是同一个
- dao 不要关 conn,在 service 统一关
建表
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
money INT
);
insert into account values(1, '张三', 1000);
INSERT INTO account VALUES(2, '李四', 1000);
select * from account;
dao
public interface AccountDao {
// dao 做更新操作,参数1 是账号,参数2 更新的金额
public void update(int id, int amount, Connection conn);
}
package com.itheima.dao;
import com.itheima.util.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
public class AccountDaoImpl implements AccountDao{
@Override
public void update(int id, int amount, Connection conn) {
// Connection conn = null;
PreparedStatement stmt = null;
try {
// conn = JdbcUtils.getConnection(); // conn1 conn2
stmt = conn.prepareStatement("update account set money = money+? where id = ?");
stmt.setInt(1, amount);
stmt.setInt(2, id);
stmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
// dao 不应该关闭 conn
JdbcUtils.close(stmt, null);
}
}
}
service 及测试
package com.itheima.service;
import com.itheima.dao.AccountDao;
import com.itheima.dao.AccountDaoImpl;
import com.itheima.util.JdbcUtils;
import java.sql.Connection;
import java.sql.SQLException;
public class AccountService {
private AccountDao dao = new AccountDaoImpl();
/**
*
* @param source 源
* @param target 目标
* @param amount 金额
*/
public void transfer(int source, int target, int amount) {
Connection conn = JdbcUtils.getConnection();
try {
conn.setAutoCommit(false);
// 转账
dao.update(source, -1*amount, conn); // 源账号减钱
int i = 1/0;
dao.update(target, amount, conn); // 目标账户加钱
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
} finally {
// service 层负责关闭连接
JdbcUtils.close(null, conn);
}
}
public static void main(String[] args) {
AccountService service = new AccountService();
service.transfer(1, 2, 500);
}
}
2. Student Dao 与三层整合(* 重点,代码要求自己写)
代码和视频见飞秋共享
选择1:页面+servlet => service => dao 自顶至低
选择2:dao => service => 页面+servlet 从下到上
步骤:
- 编写 dao 的接口和实现
- 编写 service 的接口和实现
- 编写 servlet
- 编写 jsp 页面
3. 连接池(会用)
- 数据库连接属于有限的资源,应当重用,而不是每次都创建新的
- 著名的连接池实现
- C3P0 外国的第三方连接池
- Druid (德鲁伊) ali 出品,第三方连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
Connection conn = dataSource.getConnection(); // 从连接池中获取一个已存在的连接
conn.close(); // 并不是真正关闭连接,而是将 conn 归还到连接池,(实际上重写了 close 方法)
Connection conn = DriverManager.getConnection(); // 每次都是创建新的连接
conn.close(); // 真正关闭了连接
配置文件 c3p0-config.xml
<c3p0-config>
<!-- 使用默认的配置读取连接池对象 -->
<default-config>
<!-- 连接参数 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://192.168.59.129:3306/db14</property>
<property name="user">root</property>
<property name="password">itheima</property>
<!-- 连接池参数 -->
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">10</property>
<property name="checkoutTimeout">3000</property>
</default-config>
</c3p0-config>
druid
// 1. 获取配置文件输入流,注意配置文件必须在 src 下
InputStream is = 工具类.class.getClassLoader().getResourceAsStream("配置文件路径");
// 2. 创建 Properties 对象
Properties prop = new Properties();
prop.load(is);
// 3. 创建连接池
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
// 4. 获取连接
Connection con = dataSource.getConnection();
// 5. 归还连接
con.close();
自定义连接池
- 思想 - close 不能真正关闭连接,而是归还到连接池
- 为了实现 close 功能的增强,MyConnection 替换了(包装了) 真正的 Connection
- 调用 close 方法时调用是MyConnection 里增强后的方法
- 调用其它方法是,间接调用了真正的 Connection 的方法