数据库开发基础(Java)
JDBC快速入门、使用JDBC开发细节、连接池与JDBC进阶使用
-
JDBC使用步骤
-
数据库查询方法
-
数据库写入方法
-
SQL注入攻击的应对
-
连接池的使用
-
Apache Commons DBUtils
JDBC快速入门
JDBC是Java中为了去方便使用各种数据而创造出来的,在java开发过程中可以使用JDBC API进而对不同的数据库进行使用。
JDBC的优点:
-
统一的API,提供一致的开发过程
-
易于学习,容易上手,代码结构稳定
-
功能强大,执行效率高,可处理海量数据
JDBC开发流程
-
加载并注册JDBC驱动
-
创建数据库连接
-
创建Statement对象
-
遍历查询结果
-
关闭连接,释放资源
public static void main(String[] args){
Connection conn=null;
try {
//1. 加载并注册JDBC驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 创建数据库连接
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/learning_jdbc?serverTimezone=UTC","root","123456"
);
//3. 创建Statement对象
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM employee");
//4. 遍历查询结果
while(rs.next()){
Integer eno= rs.getInt(1);
String name = rs.getString("ename");
Float salary = rs.getFloat("salary");
String dname = rs.getString("dname");
Date hiredate = rs.getDate("hiredate");
System.out.println(eno+"-"+name+"-"+salary+"-"+dname+"-"+ hiredate);
}
}catch (Exception e){
e.printStackTrace();
}finally {
try {
//5. 关闭连接,释放资源
if (conn != null && conn.isClosed() == false){
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
JDBC开发流程细节
各数据库与连接字符串:
JDBC连接的对象Connection,通过TCP/IP协议,连通JDBC应用(Java程序)与MySQL数据库服务器的3306端口
//2. 创建数据库连接
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/learning_jdbc?serverTimezone=UTC","root","123456"
)
其中的参数包括了连接字符串与数据库用户名和密码
MySQL连接字符串:
-
格式:jdbc:mysql://主机ip:端口/数据库名?参数列表
-
主机ip与端口是可选设置,默认值为127.0.0.1与3306
-
参数列表采用url编码,格式:参数1=值1&参数2=值2&..
-
SQL注入攻击问题:
-
SQL注入攻击是指利用SQL漏洞越权获取数据的黑客行为
-
SQL注入攻击根源是对原始SQL中的敏感字符做特殊处理
-
解决方法:放弃Statement改用PrepareStatement处理SQL
-
Statement方法对符号单引号没有进行处理,会被SQL注入,使用PreStatement能防范SQL注入。
-
PrepareStatement
-
PrepareStatement预编译Statement是Statement的子接口
-
PrepareStatement对SQL进行参数化,预防SQL注入攻击
-
PreparedStatement比Statement执行效率更高
-
String pdname = in.nextLine(); String pdname = "市场部";//输入参数 Connection conn=null; try { //1. 加载并注册JDBC驱动 Class.forName("com.mysql.cj.jdbc.Driver"); //2. 创建数据库连接 conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/learning_jdbc?serverTimezone=UTC","root","123456" ); //3. 创建Statement对象 String sql = "SELECT * FROM employee WHERE dname=?"; PreparedStatement pStmt = conn.prepareStatement(sql); pStmt.setString(1,pdname); ResultSet rs = pStmt.executeQuery("SELECT * FROM employee WHERE dname='"+ pdname+"'"); //4. 遍历查询结果 while(rs.next()){ Integer eno= rs.getInt(1); String name = rs.getString("ename"); Float salary = rs.getFloat("salary"); String dname = rs.getString("dname"); Date hiredate = rs.getDate("hiredate"); System.out.println(eno+"-"+name+"-"+salary+"-"+dname+"-"+ hiredate); } }catch (Exception e){ e.printStackTrace(); }finally { try { //5. 关闭连接,释放资源 if (conn != null && conn.isClosed() == false){ conn.close(); } } catch (SQLException throwables) { throwables.printStackTrace(); } }
时间:2024-05-19日,星期天
JDBC进行数据库操作
将上面的数据库连接和数据库连接资源关闭方法进行封装,得到DBUtils,数据库工具文件
package com.imooc.jdbc.common;
import java.sql.*;
public class DBUtils {
/**
* 获取数据库连接
* @return返回数据库连接
* @throws ClassNotFoundException
* @throws SQLException
*/
public static Connection getConnection() throws ClassNotFoundException, SQLException {
//1. 加载并注册JDBC驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 创建数据库连接
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/learning_jdbc?serverTimezone=UTC","root","123456"
);
return conn;
}
/**
* 关闭数据库连接相关资源
* @param rs 数据库返回结果集
* @param stmt 数据库预处理查询语句
* @param conn 数据库连接
*/
public static void closeConnection(ResultSet rs, Statement stmt, Connection conn){
if (rs !=null){
try {
//关闭结果连接,释放资源
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stmt != null){
try {
//关闭连接,释放资源
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
try {
//5. 关闭连接,释放资源
if (conn != null && conn.isClosed() == false){
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
JDBC执行插入操作
public class InsertCommand implements Command{
@Override
public void execute() {
Scanner in = new Scanner(System.in);
System.out.println("请输入员工编号:");
int eno = in.nextInt();
System.out.println("请输入员工姓名:");
String ename = in.next();
System.out.println("请输入员工薪资:");
float salary = in.nextFloat();
System.out.println("请输入隶属部门");
String dname = in.next();
Connection conn = null;
PreparedStatement pStmt = null;
try {
conn = DBUtils.getConnection();
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();//执行更新方法,返回插入的条数
System.out.println("数据新增成功条数:"+cnt);
System.out.println(ename+"已成功办理入职");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
DBUtils.closeConnection(null,pStmt,conn);
}
}
}
JDBC执行更新和删除操作
//更新
/调整员工薪资 public class UpdateCommand implements Command { @Override public void execute() { Scanner in = new Scanner(System.in); System.out.println("请输入要调整的员工编号"); int eno = in.nextInt(); System.out.println("请输入要调整到的薪资"); float salary = in.nextFloat(); Connection conn = null; PreparedStatement pStmt = null; try { conn = DBUtils.getConnection(); 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("员工编号"+eno+"薪资已调整到"+salary); }else{ System.out.println("未找到员工编号为:"+eno+"的员工"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); }finally { DBUtils.closeConnection(null,pStmt,conn); } } }
//删除
public class DeleteCommand implements Command{ @Override public void execute() { Scanner in = new Scanner(System.in); System.out.println("请输入要删除的员工编号"); int eno = in.nextInt(); System.out.println("请输入要删除的员工姓名"); String enmae = in.next(); Connection conn = null; PreparedStatement pStmt = null; try { conn = DBUtils.getConnection(); String sql = "DELETE FROM employee WHERE eno = ? AND ename = ?"; pStmt = conn.prepareStatement(sql); pStmt.setInt(1,eno); pStmt.setString(2,enmae); int cnt = pStmt.executeUpdate(); if (cnt == 1){ System.out.println("cnt:"+cnt); System.out.println("员工编号"+eno+",姓名"+enmae+"的员工已删除"); }else { System.out.println("员工编号"+eno+",姓名"+enmae+"的员工未找到"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException throwables) { throwables.printStackTrace(); }finally { DBUtils.closeConnection(null,pStmt,conn); } } }
更新和删除操作的方法主要区别是sql语句的不同,其它的内容大致相似。
JDBC的事务管理
JDBC中允许两种事务模式,分别是自动提交和手动提交模式
-
自动提交事务模式
-
自动提交模式是指每执行一次写操作SQL,自动提交事务
-
自动提交开启方法:conn.setAutoCommit(true)
-
自动事务是JDBC默认行为,此模式无法保证多数据一致性
-
-
手动提交事务模式
-
手动提交模式是指显式调用commit()与rollback()方法管理事务
-
手动提交开启方法;conn.setAutoCommit(flase)
-
手动提交事务可保证多数据一致性,但必须手动调用提交/回滚方法
-
//手动提交事务案例
//JDBC事务管理,演示案例批量添加员工 public class TransactionSample { public static void main(String[] args) { Connection conn = null; PreparedStatement pStmt = null; try { conn = DBUtils.getConnection(); conn.setAutoCommit(false);//开启jdbc手动提交事务,,自动提交事务时默认为true String sql = "insert into employee(eno,ename,salary,dname) values(?,?,?,?)"; pStmt = conn.prepareStatement(sql); for (int i=1000; i<2000; i++){ if (i==1005){ // throw new RuntimeException("插入失败"); //注释后,不抛异常,正常执行 } pStmt.setInt(1,i); pStmt.setString(2,"员工"+i); pStmt.setFloat(3,4000f); pStmt.setString(4,"市场部"); pStmt.executeUpdate(); } conn.commit();//手动提交情况下才能显式使用 } catch (Exception e) { try { conn.rollback();//回滚数据,手动提交情况下才能使用 } catch (SQLException throwables) { throwables.printStackTrace(); } } finally { DBUtils.closeConnection(null,pStmt,conn); } } }
JDBC对时间类型的处理
//将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(strHireadate); } 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);
数据库连接池
阿里巴巴Druid连接池
Druid是阿里巴巴开源连接池组件,Druid对数据库连接进行有效管理与重用,最大化程序执行效率,连接池负责创建管理连接,程序只负责取用与归还
连接Druid连接池(配置和使用)
//配置使用Druid连接池 public class DruidSample { public static void main(String[] args) { //1.加载属性文件 Properties properties = new Properties(); String propertyFile = DruidSample.class.getResource("/druid-config.properties").getPath(); try { propertyFile = new URLDecoder().decode(propertyFile, "UTF-8");//解析文件,避免错误 properties.load(new FileInputStream(propertyFile)); } catch (Exception e) { e.printStackTrace(); } Connection conn = null; PreparedStatement pStmt = null; ResultSet rs = null; try { //2.获取DataSource数据源对象 DataSource dataSource = DruidDataSourceFactory.createDataSource(properties); //创建数据库连接 conn = dataSource.getConnection(); pStmt = conn.prepareStatement("select * from employee limit 0,5"); rs = pStmt.executeQuery(); while(rs.next()){ Integer eno= rs.getInt(1); String name = rs.getString("ename"); Float salary = rs.getFloat("salary"); String dname = rs.getString("dname"); Date hiredate = rs.getDate("hiredate"); System.out.println(eno+"-"+name+"-"+salary+"-"+dname+"-"+ hiredate); } } catch (Exception e) { e.printStackTrace(); }finally { DBUtils.closeConnection(rs,pStmt,conn); } } }
Apache Commons DBUtils
-
commons-dbutils是Apache提供的开源JDBC工具类库
-
它是对JDBC的简单封装,学习成本极低
-