什么是JDBC
Java数据库连接 - Java DataBase Connectivity JDBC可以让Java通过程序操作关系型数据库 JDBC基于驱动程序实现与数据库的连接与操作
JDBC的优点
- 统一的API,提供开发过程
- 易于学习,容易上手,代码结构稳定
- 功能强大,执行效率高,可处理海量数据
快速上手JDBC
JDBC开发细节
获取JDBC驱动Jar
MySQL :: MySQL Connectors
创建数据库连接代码
- Calss.forName用于加载指定的JDBC驱动类,本质是通知JDBC注册这个驱动类,驱动由数据库厂商自行开发,连接字符串也不同
数据库连接配置
DriverManager
DriverManager:用于注册/管理JDBC驱动程序
DriverManager.getConnection(连接字符串,用户名,密码)
返回值Connection对象,对应数据库的物理网络连接
Connection 对象
Connection对象用于JDBC与数据库的网络通信对象
java.sql.Connection是一个接口,具体由驱动厂商实现
所有数据库的操作都建立在Connection基础之上
MySQL连接字符串
格式:jdbc.mysql://[主机ip] [:端口]/数据库名?参数列表
主机ip与端口是可选设置,默认值为127.0.0.1与3306
参数列表采用url编码,格式:参数1=值1&参数2=值2&…
MySQL连接字符串常用参数
JDBC的查询操作及SQL注入漏洞
PreparedStatement:主要解决SQL注入问题
SQL注入攻击
SQL注入攻击是指利用SQL漏洞越权获取数据的黑客行为
SQL注入攻击根源是对原始SQL中的敏感字符做处理
解决方法:放弃Statement改用PreparedStatement处理SQL
PreparedStatement
PreparedStatement 预编译 Statement 是 Statement 的子接口
PreparedStatement 对SQL进行参数化,预防注入攻击
PreparedStatement 比 Statement 执行效率更高
错误使用方式
JDBC工具类的抽取及增删改查
封装DbUtils工具类
代码语言:javascript复制 public class DbUtils {
/**
* 创建新的数据库连接
* @return 新的Connection对象
* @throws SQLException
* @throws ClassNotFoundException
*/
public static Connection getConnection() throws SQLException, ClassNotFoundException {
//1. 加载并注册JDBC驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 创建数据库连接
String url = "jdbc:mysql://localhost:3306/imooc?useSSL=false&useUnicode=true&characterEncoding=UTF-8&severTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
Connection conn = DriverManager.getConnection(url, "root", "123456");
return conn;
}
/**
* 关闭连接,释放资源
* @param rs 结果集对象
* @param stmt Statement对象
* @param conn Connection对象
*/
public static void closeConnection(ResultSet rs, Statement stmt, Connection conn) {
//5. 关闭连接,释放资源
try {
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (stmt != null) {
stmt.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn != null && !conn.isClosed()) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
JDBC实现新增数据
代码语言:javascript复制String sql = "insert into employee(eno,ename,salary,dname) values(?,?,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, eno);
pstmt.setString(2, ename);
pstmt.setFloat(3, salary);
pstmt.setString(4, dname);
int cnt = pstmt.executeUpdate(); //所有写操作都用 executeUpdate,且返回值为整型,代表本次执行所影响的记录数
实现JDBC更新与删除数据
代码语言:javascript复制 String sql = "update employee set salary=? where eno=?";
pstmt = conn.prepareStatement(sql);
pstmt.setFloat(1, salary);
pstmt.setInt(2, eno);
int cnt = pstmt.executeUpdate();
if (cnt == 1) {
System.out.println("运功薪资以调成完成!");
} else {
System.out.println("没有找到编号:" eno ",员工的数据。");
}
代码语言:javascript复制 conn = DbUtils.getConnection();
String sql = "delete from employee where eno = ?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, eno);
int cnt = pstmt.executeUpdate();
if (cnt == 1) {
System.out.println("员工数据以删除!");
} else {
System.out.println("没有找到编号:" eno ",员工的数据。");
}
JDBC中的事务管理
事务是以一种可靠的、一致的方式,访问和操作数据库的程序单元 事务依赖于数据库实现,MySQL通过事务区作为数据缓冲地带
手动事务开发
代码语言:javascript复制public class TransactionSample {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = DbUtils.getConnection();
//JDBC默认使用自动提交的模式
conn.setAutoCommit(false);//关闭自动提交
String sql = "insert into employee(eno,ename,salary,dname) values (?,?,?,?)";
for (int i = 1000; i < 1020; i ) {
if (i == 1005) {
// throw new RuntimeException("插入失败");
}
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, i);
pstmt.setString(2, "员工" i);
pstmt.setFloat(3, 4000f);
pstmt.setString(4, "市场部");
pstmt.executeUpdate();
}
conn.commit();//提交数据
} catch (Exception e) {
e.printStackTrace();
try {
if (conn != null && !conn.isClosed()) {
conn.rollback();//数据回滚
}
} catch (SQLException ex) {
ex.printStackTrace();
}
} finally {
DbUtils.closeConnection(null, pstmt, conn);
}
}
}
JDBC的日期处理及批量处理
Date日期对象的处理
代码语言:javascript复制 //String到Java.sql.Date分为两步
//1.String转为Java.util.Date
java.util.Date udHiredate = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
udHiredate = sdf.parse(strHiredate);
} catch (ParseException e) {
e.printStackTrace();
}
//2.java.util.Date转为Java.sql.Date
long time = udHiredate.getTime(); //获取从1970年到现在的毫秒数
java.sql.Date sdHiredate = new java.sql.Date(time);
数据批处理
代码语言:javascript复制 long startTime = new Date().getTime();
conn = DbUtils.getConnection();
//JDBC默认使用自动提交的模式
conn.setAutoCommit(false);//关闭自动提交
String sql = "insert into employee(eno,ename,salary,dname) values (?,?,?,?)";
for (int i = 100000; i < 200000; i ) {
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, i);
pstmt.setString(2, "员工" i);
pstmt.setFloat(3, 4000f);
pstmt.setString(4, "市场部");
pstmt.executeUpdate();
}
conn.commit();//提交数据
long endTime = new Date().getTime();
System.out.println("tc1执行时长:" (endTime-startTime));
代码语言:javascript复制 long startTime = new Date().getTime();
conn = DbUtils.getConnection();
//JDBC默认使用自动提交的模式
conn.setAutoCommit(false);//关闭自动提交
String sql = "insert into employee(eno,ename,salary,dname) values (?,?,?,?)";
pstmt = conn.prepareStatement(sql);
for (int i = 200000; i < 300000; i ) {
pstmt.setInt(1, i);
pstmt.setString(2, "员工" i);
pstmt.setFloat(3, 4000f);
pstmt.setString(4, "市场部");
pstmt.addBatch();//将参数加入批处理任务
// pstmt.executeUpdate();
}
pstmt.executeBatch();//指向批处理任务
conn.commit();//提交数据
long endTime = new Date().getTime();
System.out.println("tc2执行时长:" (endTime-startTime));
连接池与JDBC进阶使用
阿里巴巴Druid连接池
Druid是阿里巴巴开源连接池组件,是最好的连接池之一
Druid对数据库连接进行有效的管理与重用,最大化程序执行效率
Druid连接池配置与使用
代码语言:javascript复制/**
* Druid连接池配置与使用
*/
public class DruidSample {
public static void main(String[] args) {
//1.加载属性文件
//创建Properties类,利用Properties对象保存druid-config.properties配置文件信息
Properties properties = new Properties();
//当前类.cslass.getReource("/文件名").getPath() 表示获取当前类路径下对应文件的路径,用String类型保存
String propertyFile = DruidSample.class.getResource("/druid-config.properties").getPath();
try {
//将propertyFile转回到UTF-8
//空格 -> c:java codedruid-config.properties
//URLDecoder().decode()将 还原到原来的空格 c:java codedruid-config.properties
propertyFile = new URLDecoder().decode(propertyFile, "UTF-8");
//使用properties.load()方法,加载propertyFile路径文件
properties.load(new FileInputStream(propertyFile));
} catch (Exception e) {
e.printStackTrace();
}
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//2.获取DateSource数据源对象
//利用DruidDataSourceFactory数据源工厂.createDataSource,将已载入的properties对象放入。
//方法返回时的数据源DataSource 选用javax.sql下的
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
//3.创建数据库连接
conn = dataSource.getConnection();
pstmt = conn.prepareStatement("select * from employee limit 0,10");
rs = pstmt.executeQuery();
while (rs.next()) {
Integer enoId = rs.getInt(1);
String ename = rs.getString("ename");
Float salary = rs.getFloat("salary");
String dname = rs.getString("dname");
System.out.println("部门:" dname " 编号:" enoId " 姓名:" ename " 工资:" salary);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DbUtils.closeConnection(rs, pstmt, conn);
}
}
}
不使用连接池:conn.close()关闭连接,使用连接池:conn.close()将连接回收至连接池
这个需要配置druid-config.properties文件,如果在程序运行中达到了maxActive上线,其余的程序一直会进入等待,等待其他正在使用连接程序调用close方法将这个数据库连接进行回收。
代码语言:javascript复制#初始的尺寸
initialSize=10
#最多不得大于20
maxActive=20
Druid连接池的配置连接数量的初始值为什么要和最大值保持一致?
是因为在我们日常工作的时候,做为应用程序,最好在一开始就把所有的连接和资源都分配好,用户进来后直接分配现成的资源避免出现重新创建资源的情况,这样对整体的程序管理和性能都有帮助。
扩展知识:C3P0连接池
在C3P0中强制配置文件名叫c3p0-config.xml文件,并且放在根路径上,在创建ComboPooledDataSource对象的时候会自动加载XML文件
并且根据XML文件,创建DataSource数据源对象
Commons DBUtils使用入门
commons-dbutils 是 Apache 提供的开源JDBC工具类库
查找
更新