JDBC
JDBC是Java访问数据库的标准规范,具体操作具体由数据库厂商实现,相当于一个数据库驱动。我们只需要会JDBC接口中的方法即可,数据库驱动(jar包)由数据库厂商提供。
导入驱动jar包:
- 创建libs文件夹
- 复制jar包到libs
- 右键libs->add as library
JDBC快速实现:
public class Test {
public static void main(String[] args) throws Exception {
// 1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2. 获取数据库连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "root");
// 3. 定义sql语句
String sql = "update stu set score=80 where id=1";
// 4. 获取sql执行对象
Statement stmt = conn.createStatement();
// 5. 执行sql
int count = stmt.executeUpdate(sql);
// 6. 处理结果
System.out.println(count);
// 7. 释放资源
stmt.close();
conn.close();
}
}
JDBC的核心API:
-
DriverManager 驱动管理对象,返回数据库连接对象
- URL参数如果是本地 可以省略
jdbc:mysql:///stu
- 处理乱码:
jdbc:mysql///stu?characterEncoding=utf8
- URL参数如果是本地 可以省略
-
Connection 数据库连接对象,用于创建一条SQL语句对象
Statement stmt = conn.createStatment();
PreparedStatment pstmt = conn.prepareStatement(sql);
-
setAutoCommit(boolean);
开始事务 -
commit();
提交事务 -
rollback();
回滚事务
-
Statement 执行静态sql对象
-
boolean execute(sql);
执行任意sql -
int executeUpdate(sql);
增删改、创建、修改、删除 -
ResultSet executeQuery(sql);
查找
-
-
PreparedStatment 执行动态sql对象
-
ResultSet:执行结果
ResultSet rs = stmt.executeQuery(sql); while (rs.next()) { int id = rs.getInt(1); // 根据列号 String name = rs.getString("name"); // 根据列名 System.out.println(id + ": " + name); }
JdbcUtils
如果一个功能经常要用到(代码重复),就把这个功能做成工具类。
解决:
- 工具类中定义许多静态方法,通过传递参数解决;
- 如果不想传参,则把参数放在配置文件
jdbc.properties
中传递; - 配置文件只需要读取一次即可,所以把读取配置文件代码放在静态代码块中。
最终如下:
- src目录下创建配置文件
jdbc.properties
url=jdbc:mysql://localhost:3306/db1
user=root
password=root
driver=com.mysql.jdbc.Driver
- 创建工具类
JDBCUtils.java
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
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();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
// 加载配置文件
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 | 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 throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(Statement stmt, Connection conn, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
close(stmt, conn);
}
}
- 数据库连接(测试工具类)
import java.sql.*;
public class JdbcDemo {
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();
stmt = conn.createStatement();
String sql = "select * from stu";
rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println(id + ": " + name);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.close(stmt, conn, rs);
}
}
}
PreparedStatment
SQL注入问题:在用户密码和数据库匹配时,如果SQL语句是:
select * from user where name=‘Tom‘ and password=‘root‘ or 1=1;
则返回所有查询结果。
所以 使用PreparedStatment匹配SQL语句中的占位符?,可以防止SQL注入问题。
// 定义sql
String sql = "select * from user where name=? and password=?";
// 获取执行sql的对象
PreparedStatement pstmt = conn.getpreparedStatement(sql);
// 赋值
pstmt.setString(1, "Tom");
pstmt.setString(2, "123");
// 执行
ResultSet rs = pstmt.executeQuery();
JDBC控制事务
使用Connection对象管理事务:
- setAutoCommit(boolean);` 开始事务:设置为false,相当于开启事务
-
commit();
提交事务 -
rollback();
回滚事务
案例:
Connection conn = null;
PrepareStatment ps = null;
try{
conn = JdbcUtils.getConnection();
conn.setAutoCommit(false); // 开启事务
ps = conn.prepareStatment("update stu set score=? where name=?");
ps.setInt(1, 90);
ps.setString(2, "张三");
ps.executeUpdate();
conn.commit(); // 提交事务
} catch () {
conn.rollback(); // 回滚事务
} finally {
JdbcUtils.close(ps, conn);
}
JDBC连接池
之前都是每次连接数据库,执行完sql立马释放资源,降低了执行效率,因此提出数据库连接池。
- 接口:javax.sql.DataSourrce,由数据库厂商实现数据库连接池
- 获取连接:
Connection conn = ds.getConnection()
- 归还连接:
conn.close()
,归还给连接池
- 获取连接:
- 常见数据连接池实现:
- C3P0:
- Druid:阿里巴巴提供
C3P0连接池技术:
- 导入jar包
- 导入
c3p0-0.9.5.2.jar
- 导入c3p0的依赖包
mchange-commons-java-0.2.12.jar
- 导入
- 定义配置文件
- 直接将配置文件
c3p0-config.xml
放在src目录下。 - 定义一下数据库等
- 直接将配置文件
- 创建数据库连接池对象
DataSource ds = new ComboPooledDataSource();
- 获取连接:
Connection conn = ds.getConnection();
Druid连接池:
连接池使用:
-
导入jar包
druid-1.0.9.jar
-
导入并定义配置文件
- 任意位置导入
druid.properties
- 任意位置导入
-
获取连接池对象:通过工厂类获取
-
获取连接对象
// 加载配置文件 InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties"); Properties pro = new Properties(); pro.load(is); // 获取连接池对象 DataSource ds = DruidDataSourceFactory.createDataSource(pro); // 获取连接对象 Connection conn = ds.getConnection();
工具类:
- 定义一个类JDBCUtils
- 提供静态代码块加载配置文件,初始化连接池对象
- 提供方法:
- 获取连接池的方法
- 获取连接方法
- 释放资源
例子,工具类代码:
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static DataSource ds;
static {
Properties pro = new Properties();
try {
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
public static void close(Statement stmt, Connection conn) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
close(stmt, conn);
}
public static DataSource getDataSource() {
return ds;
}
}
工具类测试代码
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class DruidDemo2 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = JDBCUtils.getConnection();
String sql = "insert into stu values(?, ?, ?, ?)";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, 5);
pstmt.setString(2, "测试");
pstmt.setInt(3, 100);
pstmt.setInt(4, 100);
int count = pstmt.executeUpdate();
System.out.println(count);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.close(pstmt, conn);
}
}
}
JDBC Template
JDBC工具类已经很好用了,但是创建连接对象、创建执行对象、执行sql语句等还是很复杂。
Spring框架对JDBC进行简单封装,提供了JDBC Template对象,简化了JDBC开发,只需要关注执行sql和结果。
-
导入JdbcTemplate的jar包(5个)
-
创建JdbcTemplate对象(依赖于数据源DataSource)
JdbcTemplate template= new JdbcTemplate(ds);
-
调用JdbcTemplate的方法完成增删改查
-
update(): 增删改
-
queryForMap(): 查询一条记录
String sql = "select * from emp where id=?"; Map<String, Object> map = temp.queryForMap(sql, 1);
-
queryForList(): 封装为List对象
String sql = "select * from emp"; List<Map<String, Object>> list = temp.queryForList(sql); for (Map<String, Object> map : list) { System.out.println(map); }
-
query(): 封装为JavaBean对象
String sql = "select * from emp"; List<Emp> list = temp.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class)); for (Emp emp : list) { System.out.println(emp); }
-
queryForObject(): 封装为基本类型对象,用于聚合函数
String sql = "select count(*) from emp"; Long total = temp.queryForObject(sql, Long.class); System.out.println(total);
-
一个简单的例子:(连接池等都是template完成,不需要自己写)
JdbcTemplate template= new JdbcTemplate(JDBCUtils.getDataSource());
String sql = "update stu set age=18 where id=?";
int count = template.update(sql, 5);
System.out.println(count);