JDBC 技术
JDBC 简介
什么是 JDBC
- JDBC(Java DataBase Connectivity)java数据库连接
- 是JavaEE平台下的技术规范
- 定义了在Java语言中连接数据库,执行SQL语句的标准
- 可以为多种关系数据库提供统一访问
什么是数据库驱动程序
- 数据库厂商对JDBC规范的具体实现
- 不同数据产品需要依赖数据库驱动来完成对数据库的操作
程序操作数据库流程
JDBC3.0 标准中常用接口与类
Driver 接口
Driver 接口的作用是来定义数据库驱动对象应该具备的一些能力。比如与数据库建立连 接的方法的定义所有支持 java 语言连接的数据库都实现了该接口,实现该接口的类我们称 之为数据库驱动类。在程序中要连接数据库,必须先通过 JDK 的反射机制加载数据库驱动类,将其实例化。不同的数据库驱动类的类名有区别。
加载 MySql 驱动:Class.forName(“com.mysql.jdbc.Driver”);
加载 Oracle 驱动:Class.forName(“oracle.jdbc.driver.OracleDriver”);
DriverManager 类
DriverManager 通过实例化的数据库驱动对象,能够建立应用程序与数据库之间建立连 接。并返回 Connection 接口类型的数据库连接对象。
常用方法
getConnection(StringjdbcUrl,Stringuser,Stringpassword)
该方法通过访问数据库的 url、用户以及密码,返回对应的数据库的 Connection 对象
JDBC URL
与数据库连接时,用来连接到指定数据库标识符。在 URL 中包括了该数据库的类型、 地址、端口、库名称等信息。不同品牌数据库的连接 URL 不同。
Connection 接口
-
Connection 与数据库的连接(会话)对象。我们可以通过该对象执行 sql 语句并返回结
果。 -
连接 MySql 数据库:
Connection conn = DriverManager.getConnection(“jdbc:mysql://host:port/database”, “user”, “password”);
-
连接 Oracle 数据库:
Connection conn = DriverManager.getConnection(“jdbc:oracle:thin:@host:port:database”, “user”,“password”);
-
连接 SqlServer 数据库:
Connection conn = DriverManager.getConnection(“jdbc:microsoft:sqlserver://host:port; DatabaseName=database”,“user”,“password”);
常用方法
-
createStatement():创建向数据库发送 sql 的 Statement 接口类型的对象。
-
preparedStatement(sql) :创建向数据库发送预编译 sql 的 PrepareSatement 接口类型的
-
prepareCall(sql):创建执行存储过程的 CallableStatement 接口类型的对象。 •
-
setAutoCommit(booleanautoCommit):设置事务是否自动提交。 •commit() :在链接上提交事务。 •
-
rollback() :在此链接上回滚事务。
Statement 接口
用于执行静态 SQL 语句并返回它所生成结果的对象。 由 createStatement 创建,用于发送简单的 SQL 语句(不支持动态绑定)。
常用方法
- execute(String sql):执行参数中的 SQL,返回是否有结果集。
- executeQuery(Stringsql):运行 select 语句,返回 ResultSet 结果集。
- executeUpdate(Stringsql):运行 insert/update/delete 操作,返回更新的行数。
- addBatch(Stringsql) :把多条 sql 语句放到一个批处理中。
- executeBatch():向数据库发送一批 sql 语句执行。
PreparedStatement 接口
继承自 Statement 接口,由 preparedStatement 创建,用于发送含有一个或多个参数的 SQL 语句。PreparedStatement 对象比 Statement 对象的效率更高,并且可以防止 SQL 注入,所以 我们一般都使用 PreparedStatement。
常用方法
- addBatch()把当前 sql 语句加入到一个批处理中。
- execute() 执行当前 SQL,返回个 boolean 值
- executeUpdate()运行 insert/update/delete 操作,返回更新的行数。
- executeQuery() 执行当前的查询,返回一个结果集对象
- setDate(intparameterIndex,Date x)向当前SQL语句中的指定位置绑定一个java.sql.Date
值。 - setDouble(int parameterIndex, double x)向当前 SQL 语句中的指定位置绑定一个 double
值 - setFloat(intparameterIndex,floatx)向当前 SQL 语句中的指定位置绑定一个 float 值
- setInt(intparameterIndex,intx)向当前 SQL 语句中的指定位置绑定一个 int 值
- setString(intparameterIndex,Stringx)向当前 SQL 语句中的指定位置绑定一个 String 值
ResultSet 接口
ResultSet 提供检索不同类型字段的方法。
常用方法
- getString(intindex)、getString(StringcolumnName) 获得在数据库里是 varchar、char 等类型的数据对象
- getFloat(intindex)、getFloat(StringcolumnName) 获得在数据库里是 Float 类型的数据对象。
- getDate(intindex)、getDate(StringcolumnName) 获得在数据库里是 Date 类型的数据。
- getBoolean(intindex)、getBoolean(StringcolumnName) 获得在数据库里是 Boolean 类型的数据。
- getObject(intindex)、getObject(StringcolumnName) 获取在数据库里任意类型的数据。
ResultSet 对结果集进行滚动的方法
- next():移动到下一行。
- Previous():移动到前一行。
- absolute(introw):移动到指定行。
- beforeFirst():移动 resultSet 的最前面。
- afterLast() :移动到 resultSet 的最后面。
CallableStatement 接口
继承自 PreparedStatement 接口,由方法 prepareCall 创建,用于调用数据库的存储过程。
JDBC执行SQL语句过程
-
注册驱动
Class.forName("com.mysql.jdbc.Driver");
-
创建连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjsxt" + "?useUnicode=true&character=utf-8", "root", "root");
-
执行SQL
String sql = "INSERT INTO departments VALUES(DEFAULT, '" + department_name + "', " + location_id + ")"; statement = conn.createStatement(); int flag = statement.executeUpdate(sql);
-
关闭连接
先关Statement,再关Connection
if (null != statement) { try { statement.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (null != conn) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
简单封装JDBC工具类
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* jdbc工具类
* //获取Connection对象
//关闭Statement
//关闭Connection
* @author ad
*
*/
public class JdbcUtil {
private static String driver = "com.mysql.jdbc.Driver";
private static String jdbcUrl = "jdbc:mysql://localhost:3306/bjsxt"
+ "?useUnicode=true&character=utf8";
private static String username = "root";
private static String password = "root";
static {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 获取Connection
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(jdbcUrl, username, password);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
/**
* 关闭Statement
* @param State
*/
public static void closeStatement(Statement state) {
if (null == state) {
try {
state.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 关闭Connection
* @param conn
*/
public static void closeConnection(Connection conn) {
if (null == conn) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//关闭资源
public static void closeResource(Connection conn, Statement state) {
closeStatement(state);
closeConnection(conn);
}
public static void main(String[] args) {
getConnection();
}
}
使用properties文件优化JDBC工具类
1.将配置信息存放到properties文件中
driver = com.mysql.jdbc.Driver
jdbcUrl = jdbc:mysql://localhost:3306/bjsxt?useUnicode=true&character=utf8
username = root
password = root
- 读取properties文件
通过ResourceBundle来读取
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
driver = bundle.getString("driver");
jdbcUrl = bundle.getString("jdbcUrl");
username = bundle.getString("username");
password = bundle.getString("password");
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
/**
* jdbc工具类
* //获取Connection对象
//关闭Statement
//关闭Connection
* @author ad
*
*/
public class JdbcUtil {
private static String driver;
private static String jdbcUrl;
private static String username;
private static String password;
static {
//读取properties文件
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
driver = bundle.getString("driver");
jdbcUrl = bundle.getString("jdbcUrl");
username = bundle.getString("username");
password = bundle.getString("password");
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 获取Connection
* @return
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(jdbcUrl, username, password);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
/**
* 关闭Statement
* @param State
*/
public static void closeStatement(Statement state) {
if (null == state) {
try {
state.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 关闭Connection
* @param conn
*/
public static void closeConnection(Connection conn) {
if (null == conn) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//关闭资源
public static void closeResource(Connection conn, Statement state) {
closeStatement(state);
closeConnection(conn);
}
public static void closeResource(Connection conn, Statement state, ResultSet reSet) {
closeStatement(state);
closeConnection(conn);
closeResultSet(reSet);
}
public static void closeResultSet(ResultSet reSet) {
if (null == reSet) {
try {
reSet.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
查询
使用Statement对象查询数据
步骤与Update大致相同,查询多了操作返回的结果集ResultSet
//查询
public void selectDepartmentsById(int departments_id) {
Connection conn = null;
Statement statement = null;
ResultSet resultSet = null;
try {
conn = JdbcUtil.getConnection();
String sql = "SELECT * FROM departments WHERE departments_id = " + departments_id;
statement = conn.createStatement();
//执行SQL
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getInt("departments_id") + ":"
+ resultSet.getString("department_name") + ":"
+ resultSet.getInt("location_id"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, statement, resultSet);
}
}
ResultSet
注意 ResultSet 中封装的并不是我们查询到的所有的结果集,而是返回了查询到的结果集的数据库游标。通过 ResultSet 中的 next()方法操作游标的位置获取结果集。
ResultSet逻辑分页
/**
* <p>currentPage 当前页数, pageRows 每页条数</p>
* @param currentPage
* @param pageRows
*/
public void selectDepartmentsPage(int currentPage, int pageRows) {
Connection conn = null;
Statement statement = null;
ResultSet resultSet = null;
try {
conn = JdbcUtil.getConnection();
String sql = "SELECT * FROM departments";
statement = conn.createStatement();
//执行SQL
resultSet = statement.executeQuery(sql);
//开始位置与结束位置
int begin = (currentPage - 1) * pageRows;
int end = currentPage * pageRows;
//当前位置的计数器
int currentNum = 0;
while (resultSet.next()) {
//控制获取结果集的数据量
if (currentNum >= begin && currentNum < end) {
System.out.println(resultSet.getInt("departments_id") + ":"
+ resultSet.getString("department_name") + ":"
+ resultSet.getInt("location_id"));
//结束操作
if (currentNum == end - 1) {
break;
}
}
currentNum++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, statement, resultSet);
}
}
SQL注入问题
什么是SQL注入
所谓 SQL 注入,就是通过把含有 SQL 语句片段的参数插入到需要执行的 SQL 语句中, 最终达到欺骗数据库服务器执行恶意操作的 SQL 命令。
/**
* 模拟SQL注入
* @author ad
*
*/
public class SQLInject {
//查询
public void selectDepartmentsById(String department_name, int location_id) {
Connection conn = null;
Statement statement = null;
ResultSet resultSet = null;
try {
conn = JdbcUtil.getConnection();
String sql = "SELECT * FROM departments WHERE department_name = '" + department_name + "' AND "
+ "location_id = " + location_id;
statement = conn.createStatement();
//执行SQL
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getInt("departments_id") + ":"
+ resultSet.getString("department_name") + ":"
+ resultSet.getInt("location_id"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, statement, resultSet);
}
}
public static void main(String[] args) {
SQLInject s = new SQLInject();
s.selectDepartmentsById("研发部 ' or 1 = 1 -- ", 8);
}
}
PreparedStatement 对象的使用
PreparedStatement 特点:
- PreparedStatement 接口继承 Statement 接口
- PreparedStatement 效率高于 Statement
- PreparedStatement 支持动态绑定参数
- PreparedStatement 具备 SQL 语句预编译能力
- 使用 PreparedStatement 可防止出现 SQL 注入问
PreparedStatement 使用示例
//使用PreparedStatement 向Departments表添加一条数据
public void insertDepartments(String department_name, int location_id) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
String sql = "INSERT INTO departments VALUES(DEFAULT, ?, ?)";
ps = conn.prepareStatement(sql);
ps.setString(1, department_name);
ps.setInt(2, location_id);
//执行SQL
int flag = ps.executeUpdate();
System.out.println("flag = " + flag);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, ps);
}
}
什么是预编译
SQL 语句的执行步骤
- 语法和语义解析
- 优化 sql 语句,制定执行计划
- 执行并返回结果
但是很多情况,我们的一条 sql 语句可能会反复执行,或者每次执行的时候只有个别的 值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。 如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行 了。
所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将 sql 语句模板化或者 说参数化
预编译语句的优势在于:一次编译、多次运行,省去了解析优化等过程;此外预编译语 句能防止 sql 注入
解析过程
**硬解析 **
在不开启缓存执行计划的情况下,每次 SQL 的处理都要经过:语法和语义的解析,优 化器处理 SQL,生成执行计划。整个过程我们称之为硬解析。
**软解析 **
如果开启了缓存执行计划,数据库在处理 sql 时会先查询缓存中是否含有与当前 SQL 语句相同的执行计划,如果有则直接执行该计划。
预编译方式
开始数据库的日志
show VARIABLES like ‘%general_log%’
set GLOBAL general_log = on
set GLOBAL log_output=‘table’
依赖数据库驱动完成预编译
如果我们没有开启数据库服务端编译,那么默认的是使用数据库驱动完成 SQL 的预编 译处理。
依赖数据库服务器完成预编译
我们可以通过修改连接数据库的 URL 信息,添加 useServerPrepStmts=true 信息开启服 务端预编译。
使用PreparedStatement 对象完成数据的更新
public void udateDempartements(int departments_id, String department_name, int location_id) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
String sql = "UPDATE departments SET department_name = ?, location_id = ? WHERE departments_id = ?";
ps = conn.prepareStatement(sql);
ps.setString(1, department_name);
ps.setInt(2, location_id);
ps.setInt(3, departments_id);
//执行SQL
int flag = ps.executeUpdate();
System.out.println("flag = " + flag);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, ps);
}
}
使用PreparedStatement 对象完成单条结果查询
public Departments selectDepartmentsById(int departmentId) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Departments dept = null;
try {
conn = JdbcUtil.getConnection();
String sql = "SELECT * FROM departments WHERE departments_id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, departmentId);
rs = ps.executeQuery();
while (rs.next()) {
dept = new Departments();
dept.setDepartmentId(rs.getInt("departments_id")) ;
dept.setDepartmentName(rs.getString("department_name"));
dept.setLocationId(rs.getInt("location_id"));
}
} catch (Exception e) {
// TODO: handle exception
} finally {
JdbcUtil.closeResource(conn, ps, rs);
}
return dept;
}
使用PreparedStatement 对象完成多条结果查询
使用容器接收结果集
/**
* 多结果查询
* @param departmentName
* @return
*/
public List<Departments> selectDepartmentsByLikeName(String departmentName) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Departments dept = null;
List<Departments> list = new ArrayList<Departments>();
try {
conn = JdbcUtil.getConnection();
String sql = "SELECT * FROM departments WHERE department_name like ?";
ps = conn.prepareStatement(sql);
ps.setString(1, "%" + departmentName + "%");
rs = ps.executeQuery();
while (rs.next()) {
dept = new Departments();
dept.setDepartmentId(rs.getInt("departments_id")) ;
dept.setDepartmentName(rs.getString("department_name"));
dept.setLocationId(rs.getInt("location_id"));
list.add(dept);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, ps, rs);
}
return list;
}
使用PreparedStatement批处理
批处理:在与数据库的一次连接中,批量的执行条 SQL 语句。
/**
* 批量添加
* @param list
*/
public void addBatch(List<Departments> list) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
String sql = "INSERT INTO departments VALUES(DEFAULT, ?, ?)";
ps = conn.prepareStatement(sql);
for (Departments departments : list) {
ps.setString(1, departments.getDepartmentName());
ps.setInt(2, departments.getLocationId());
//添加批处理
ps.addBatch();
}
//执行SQL
int[] flag = ps.executeBatch();
for (int i : flag) {
System.out.println(i);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, ps);
}
}
JDBC中的事务处理
在 JDBC 操作中数据库事务默认为自动提交。如果事务需要修改为手动提交,那么我们 需要使用 Connection 对象中的 setAutoCommit 方法来关闭事务自动提交。然后通过 Connection 对象中的 commit 方法与 rollback 方法进行事务的提交与回滚。
在exexute之前设置都有效
//关闭自动提交
conn.setAutoCommit(false);
//手动提交
conn.commit();
//在异常中使用
conn.rollback();
所有的DML操作建议都使用手动提交。
多条DML操作只要出现异常,所有的操作都会回滚。
/**
* 删除操作
* 手动提交事务
* @param departmentId
*/
public void deleteDepartmentById(int departmentId) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
//关闭自动提交
conn.setAutoCommit(false);
String sql = "DELETE FROM departments WHERE departments_id = ?";
ps = conn.prepareStatement(sql);
ps.setInt(1, departmentId);
System.out.println(ps.executeUpdate());
//手动提交
conn.commit();
} catch (Exception e) {
//出现异常,回滚
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, ps);
}
}
JDBC进阶
动态查询
根据用户给定的条件,来决定执行什么样的查询。
不给定条件时查询表中所有的数据
/**
* 动态查询
* @param sqlDept
* @return
*/
public List<Departments> selectDepartmentByProperty(Departments sqlDept) {
List<Departments> list = new ArrayList<Departments>();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Departments dept = null;
try {
conn = JdbcUtil.getConnection();
String sql = genSQL(sqlDept);
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
dept = new Departments();
dept.setDepartmentId(rs.getInt("departments_id"));
dept.setDepartmentName(rs.getString("department_name"));
dept.setLocationId(rs.getInt("location_id"));
list.add(dept);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, ps, rs);
}
return list;
}
/**
* 拼接SQL
* @param sqlDept
* @return
*/
private String genSQL(Departments dept) {
StringBuilder sb = new StringBuilder("SELECT * FROM departments WHERE 1 = 1 ");
if (null != dept) {
if (0 < dept.getDepartmentId()) {
sb.append("and departments_id = ").append(dept.getDepartmentId());
}
if (null != dept.getDepartmentName()) {
sb.append("and department_name = '").append(dept.getDepartmentName() + "'");
}
if (0 < dept.getLocationId()) {
sb.append("and location_id = ").append(dept.getLocationId());
}
}
return sb.toString();
}
应用程序分层
应用程序通过创建不同的包来实现项目的分层,将项目中的代码根据功能做具体划分, 并存放在不同的包下。
分层优点
- 分层结构将应用系统划分为若干层,每一层只解决问题的一部分,通过各层的协作 提供整体解决方案。大的问题被分解为一系列相对独立的子问题,局部化在每一层中,这样 就有效的降低了单个问题的规模和复杂度,实现了复杂系统的第一步也是最为关键的一步分 解。
- 分层结构具有良好的可扩展性,为应用系统的演化增长提供了一个灵活的支持,具 有良好的可扩展性。增加新的功能时,无须对现有的代码做修改,业务逻辑可以得到最大限 度的重用。
- 分层架构易于维护。在对系统进行分解后,不同的功能被封装在不同的层中,层与 层之间的耦合显著降低。因此在修改某个层的代码时,只要不涉及层与层之间的接口,就不 会对其他层造成严重影响。
三层结构
三层结构就是将整个业务应用划分为:界面层(User Interface layer)、业务逻辑层 (BusinessLogicLayer)、数据访问层(Dataaccesslayer)。区分层次的目的即为了“高内 聚低耦合”的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。
项目分层
commos包:存放工具类
dao.impl:数据访问层,存放操作数据库的代码
pojo:模型层,存放实体对象
service:业务层,负责处理相应的业务
在分层结构中实现业务
持久层
持久层的方法要原子化,提高复用率。
接口
public interface DepartmentsDao {
public List<Departments> selectDeptByName(String deptName);
public void insertDept(Departments dept);
}
实现类
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.trf.commos.JdbcUtil;
import com.trf.dao.DepartmentsDao;
import com.trf.pojo.Departments;
public class DepartmentsDaoImpl implements DepartmentsDao {
@Override
public List<Departments> selectDeptByName(String deptName) {
List<Departments> list = new ArrayList<Departments>();
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Departments d = null;
try {
conn = JdbcUtil.getConnection();
ps = conn.prepareStatement("SELECT * FROM departments WHERE department_name = ?");
ps.setString(1, deptName);
rs = ps.executeQuery();
while (rs.next()) {
d = new Departments();
d.setDepartmentId(rs.getInt("departments_id"));
d.setDepartmentName(rs.getString("department_name"));
d.setLocationId(rs.getInt("location_id"));
list.add(d);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, ps);
}
return list;
}
@Override
public void insertDept(Departments dept) {
Connection conn = null;
PreparedStatement ps = null;
try {
conn = JdbcUtil.getConnection();
conn.setAutoCommit(false);
ps = conn.prepareStatement("INSERT INTO departments VALUES(DEFAULT, ?, ?)");
ps.setString(1, dept.getDepartmentName());
ps.setInt(2, dept.getLocationId());
ps.executeUpdate();
conn.commit();
} catch (Exception e) {
e.printStackTrace();
JdbcUtil.rollback(conn);
} finally {
JdbcUtil.closeResource(conn, ps);
}
}
}
业务层
接口
import java.util.List;
import com.trf.pojo.Departments;
public interface DepartmentsService {
public void addDepartments(Departments dept);
public List<Departments> selectDepartmentsByName(String deptName);
}
实现类
import java.util.List;
import com.trf.dao.DepartmentsDao;
import com.trf.dao.impl.DepartmentsDaoImpl;
import com.trf.pojo.Departments;
import com.trf.service.DepartmentsService;
public class DepartmentsServiceImpl implements DepartmentsService {
@Override
public void addDepartments(Departments dept) {
DepartmentsDao deptDao = new DepartmentsDaoImpl();
deptDao.insertDept(dept);
}
@Override
public List<Departments> selectDepartmentsByName(String deptName) {
DepartmentsDao deptDao = new DepartmentsDaoImpl();
return deptDao.selectDeptByName(deptName);
}
}
测试
import java.util.List;
import com.trf.pojo.Departments;
import com.trf.service.DepartmentsService;
import com.trf.service.impl.DepartmentsServiceImpl;
public class Test {
public static void main(String[] args) {
Departments dept = new Departments();
dept.setDepartmentName("闻达共享单车洗菜部");
dept.setLocationId(5);
DepartmentsService ds = new DepartmentsServiceImpl();
//ds.addDepartments(dept);
List<Departments> list = ds.selectDepartmentsByName("闻达共享单车洗菜部");
System.out.println(list);
}
}
封装通用的BaseDao
BaseDao
/**
* 通用DML操作接口
* @author ad
*
*/
public interface BaseDao {
/**
*
* @param sql 需要执行的DML语句
* @param param 参数
* @return
*/
public int executeUpdate(String sql, Object ... param);
}
BaseDaoImpl
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import com.trf.commos.JdbcUtil;
import com.trf.dao.BaseDao;
public class BaseDaoImpl implements BaseDao{
/**
* 封装通用的DML操作
* @author ad
*
*/
public int executeUpdate(String sql, Object... param) {
Connection conn = null;
PreparedStatement ps = null;
int rows = 0;
try {
conn = JdbcUtil.getConnection();
conn.setAutoCommit(false);
ps = conn.prepareStatement(sql);
//得到参数的个数
ParameterMetaData pmd = ps.getParameterMetaData();
//绑定参数
for (int i = 1; i <= pmd.getParameterCount(); i++) {
ps.setObject(i, param[i-1]);
}
rows = ps.executeUpdate();
conn.commit();
} catch (Exception e) {
e.printStackTrace();
JdbcUtil.rollback(conn);
} finally {
JdbcUtil.closeResource(conn, ps);
}
return rows;
}
}
Dao层接口
import java.util.List;
import com.trf.pojo.Departments;
/**
* 持久层的方法要原子化,提高复用率
* @author ad
*
*/
public interface DepartmentsDao extends BaseDao{
/**
* 更新
* @param dept
* @return
*/
public int updateDept(Departments dept);
/**
* 删除
* @param dept
* @return
*/
public int deleteDeptById(Departments dept);
}
Dao层实现类
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import com.trf.commos.JdbcUtil;
import com.trf.dao.BaseDao;
import com.trf.dao.DepartmentsDao;
import com.trf.pojo.Departments;
public class DepartmentsDaoImpl extends BaseDaoImpl implements DepartmentsDao {
/**
* 更新部门信息
*/
public int updateDept(Departments dept) {
String sql = "UPDATE departments set department_name = ?, location_id = ? WHERE departments_id = ?";
return this.executeUpdate(sql, dept.getDepartmentName(), dept.getLocationId(), dept.getDepartmentId());
}
/**
* 删除部门信息
*/
public int deleteDeptById(Departments dept) {
String sql = "DELETE FROM departments WHERE departments_id = ?";
return this.executeUpdate(sql, dept.getDepartmentId());
}
}
Service层接口
import java.util.List;
import com.trf.pojo.Departments;
public interface DepartmentsService {
/**
* 更新
* @param dept
* @return
*/
public int modifyDepartments(Departments dept);
/**
* 删除
* @param dept
* @return
*/
public int deleteDepartmentsById(Departments dept);
}
Service层实现类
import com.trf.dao.DepartmentsDao;
import com.trf.dao.impl.DepartmentsDaoImpl;
import com.trf.pojo.Departments;
import com.trf.service.DepartmentsService;
public class DepartmentsServiceImpl implements DepartmentsService {
@Override
public int modifyDepartments(Departments dept) {
DepartmentsDao deptDao = new DepartmentsDaoImpl();
return deptDao.updateDept(dept);
}
@Override
public int deleteDepartmentsById(Departments dept) {
DepartmentsDao deptDao = new DepartmentsDaoImpl();
return deptDao.deleteDeptById(dept);
}
}
封装查询操作
BaseDao接口
/**
* 通用操作接口
* @author ad
*
*/
public interface BaseDao {
/**
* 通用查询方法
* @param <T>
* @param sql 需要执行的查询语句
* @param clazz 返回集合的泛型
* @param param 查询的参数
* @return
*/
public <T>List<T> find(String sql, Class<T> clazz, Object ... param);
}
BaseDao实现类
public class BaseDaoImpl implements BaseDao{
/**
* <p>实现通用查询方法</p>
* <p><T> List<T>:泛型方法</p>
* <p>通用查询方法要求实体模型成员变量名与数据库字段名相对应</p>
*/
@Override
public <T> List<T> find(String sql, Class<T> clazz, Object... param) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
List<T> list = new ArrayList<T>();
try {
conn = JdbcUtil.getConnection();
ps = conn.prepareStatement(sql);
//得到参数的个数
ParameterMetaData pmd = ps.getParameterMetaData();
for (int i = 0; i < pmd.getParameterCount(); i++) {
ps.setObject(i + 1, param[i]);
}
//处理结果集
rs = ps.executeQuery();
//获取结果集信息
ResultSetMetaData rsmd = rs.getMetaData();
while (rs.next()) {
//使用反射完成ORM
T bean = clazz.newInstance();
for (int i = 0; i < rsmd.getColumnCount(); i++) {
//获得列名
String columnName = rsmd.getColumnName(i + 1);
//获得值
Object value = rs.getObject(columnName);
//使用BeanUtil工具类将值存放到对象中
BeanUtils.setProperty(bean, columnName, value);
}
list.add(bean);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtil.closeResource(conn, ps);
}
return list;
}
}
Dao接口
/**
* 持久层的方法要原子化,提高复用率
* @author ad
*
*/
public interface DepartmentsDao extends BaseDao{
public int deleteDeptById(Departments dept);
/**
* 部门名Like查询
* @param deptName
* @return
*/
public List<Dept> selectDeptByLikeName(String deptName);
}
Dao实现类
public class DepartmentsDaoImpl extends BaseDaoImpl implements DepartmentsDao {
@Override
public List<Dept> selectDeptByLikeName(String deptName) {
String sql = "SELECT * FROM departments WHERE department_Name LIKE ?";
return this.find(sql, Dept.class, "%" + deptName + "%");
}
}
Service接口
public interface DepartmentsService {
/**
* 部门名Like查询
* @param deptName
* @return
*/
public List<Dept> findDeptByLikeName(String deptName);
}
Service接口实现类
public class DepartmentsServiceImpl implements DepartmentsService {
@Override
public List<Dept> findDeptByLikeName(String deptName) {
DepartmentsDao deptDao = new DepartmentsDaoImpl();
return deptDao.selectDeptByLikeName(deptName);
}
}
JDBC驱动加载原理
创建对象的方式
创建对象时三个重要的步骤
- 通过类加载器加载 class
- 初始化所有静态部分
- 为新生对象分配内存
MySQL驱动类的实例化过程
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
-
在使用Class.forName(“com.mysql.jdbc.Driver”)注册数据库驱动时,完成了Driver类的加载 ,和Driver类的静态初始化。
-
Driver类在静态初始化时通过反射实例化自身,并将对象交给DriverManager类进行管理;
-
所以才可以通过DriverManager.getConnection()获取数据库连接。