全称:Java DataBase Connection
译名:Java数据库连接
JDBC的来源:
最早在Java提出连接数据库需求的时候,Java的做法是:Java根据不同数据库的特点,针对每一种数据库都提出了一套代码,在使用不同的数据库和Java进行连接的时候,使用不同的代码。
缺点:
优点:
public class TestJDBC {
public static void main(String[] args) {
Connection conn = null;
Statement stat = null;
ResultSet set = null;
try {
//[1]加载JDBC驱动
// Driver driver = new orcale.driver.jdbc.orcaleDriver();
/*
* Class.forName()方法会通过你提供的类路径找到这个类并加载进入虚拟机
* 最重要的是,这个过程不需要实例化对象
*/
Class.forName("oracle.jdbc.driver.OracleDriver");
//[2]创建数据库连接对象
String url = "jdbc:orcale:thin:@localhost:1521:orcl";
String username = "数据库用户名";
String password = "数据库密码";
conn = DriverManager.getConnection(url, username, password);
//[3]创建Statement对象,编写SQL语句
String sql = "select * from employees"; //注意:此时SQL语句的结尾不要有字符的分号
stat = conn.createStatement();
//[4]通过Statement对象执行SQL语句,得到一个ResultSet结果集
set = stat.executeQuery(sql);
//[5]获取结果集中的数据,分析数据
/*
* 比较ResultSet和Iterator中的next()方法:
* Iterator:
* 在迭代器中,hasNext()方法返回boolean值,专门用来判断是否还有下一条记录
* 但是不会移动记录的位指针
* 迭代器中的next()方法,不仅负责向下移动位指针,还负责将下一条记录进行返回
*
* ResultSet:
* ResultSet的next()方法即负责向下判断是否还存在下一条记录
* 也负责在存在下一条记录的时候,移动位指针,返回下一条记录
*
* ResultSet.next() = Iterator.hasNext() + Iterator.next()
*/
while(set.next()) { //使用while循环负责遍历记录
//使用下面的7条代码负责遍历一条记录中的7个字段
System.out.print(set.getInt("emp_id") + ", "); //emp_id
System.out.print(set.getString("emp_name") + ", "); //emp_name
System.out.print(set.getString("emp_gender") + ", "); //emp_gender
System.out.print(set.getDouble("emp_salary") + ", "); //emp_salary
System.out.print(set.getDate("emp_birth") + ", "); //emp_birth
System.out.print(set.getDouble("commission_pct") + ", "); //commission_pct
System.out.println(set.getInt("dept_id")); //dept_id
}
}catch(Exception e) {
e.printStackTrace();
}finally {
//[6]关闭结果集对象,关闭Statement对象,关闭连接对象
try {
if(set != null) { //关闭ResultSet
set.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(stat != null) { //关闭Statement
stat.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn != null) { //关闭Connection
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Properties配置文件的读写:
jdbc.driver=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:orcale:thin:@localhost:1521:orcl
jdbc.username=数据库用户名
jdbc.password=数据库密码
Properties pro = new Properties();
//将处于源码包中(src文件夹)中的配置文件以Properties流的方式进行返回,读入JVM内存中
InputStream is = TestJDBC.class.getResourceAsStream("/jdbc.properties");
//将流中保存的键值对信息读入Properties对象中,顺便解析成为键值对
pro.load(is);
//通过键找到值,找到的值就是配置信息
jdbcDriver = pro.getProperty("jdbc.driver");
jdbcUrl = pro.getProperty("jdbc.url");
jdbcUsername = pro.getProperty("jdbc.username");
jdbcPassword = pro.getProperty("jdbc.password");
使用PreparedStatement替换Statement对象:
//[3]创建Statement对象,编写SQL语句
String arg = "8000 or 1=1"; //这是一个查询参数
String sql = "select * from employees where emp_salary > " + arg;
stat = conn.createStatement();
//[4]通过Statement对象执行SQL语句,得到一个ResultSet结果集
set = stat.executeQuery(sql);
PreparedStatement stat = null;
//String arg = "8000 or 1=1"; //这是一个查询参数
String sql = "select * from employees where emp_salary > ?"; //在SQL语句中,所有的条件下,都使用?作为参数占位符
stat = conn.prepareStatement(sql); //此时stat对象的来源已经是通过conn预编译得到
//[4]通过Statement对象执行SQL语句,得到一个ResultSet结果集
stat.setDouble(1, 8000.0); //按照参数占位符的序号,为所有的?赋予参数
set = stat.executeQuery(); //注意:在使用PreparedStatement对象执行SQL语句的时候,执行方法中不要再次传递SQL语句
通过POJO对象封装查询结果:
1.回忆数据库中概念和Java中概念的对应关系:
2.代码实现:
创建和数据表表名、字段对应的POJO类:
public class Employee implements Serializable {
private static final long serialVersionUID = -2675232990254926945L;
//在POJO类当中,所有的字段类型推荐使用包装类类型
private Integer empId; //注意:在POJO类属性当中,所有的属性都不使用_(下划线),下划线是两个单词的界定,Java中的属性名使用驼峰命名法
private String empName;
private String empGender;
private Double empSalary;
private Date empBirth;
private Double commissionPct;
private Integer deptId;
//空构造
public Employee() {
super();
}
//有参构造
public Employee(Integer empId, String empName, String empGender, Double empSalary, Date empBirth,
Double commissionPct, Integer deptId) {
super();
this.empId = empId;
this.empName = empName;
this.empGender = empGender;
this.empSalary = empSalary;
this.empBirth = empBirth;
this.commissionPct = commissionPct;
this.deptId = deptId;
}
//公有的getset方法
public Integer getEmpId() {
return empId;
}
/*
* 属性的set方法一定注意命名格式:驼峰命名法
* 属性:EmpId -> setEmpId -> empId
* 要求:所有属性的首字母小写
*
* 关于属性的get方法
* boolean类型的属性值不要用is开头
* Boolean isWorking -> isWorking() -> working
*/
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getEmpGender() {
return empGender;
}
public void setEmpGender(String empGender) {
this.empGender = empGender;
}
public Double getEmpSalary() {
return empSalary;
}
public void setEmpSalary(Double empSalary) {
this.empSalary = empSalary;
}
public Date getEmpBirth() {
return empBirth;
}
public void setEmpBirth(Date empBirth) {
this.empBirth = empBirth;
}
public Double getCommissionPct() {
return commissionPct;
}
public void setCommissionPct(Double commissionPct) {
this.commissionPct = commissionPct;
}
public Integer getDeptId() {
return deptId;
}
public void setDeptId(Integer deptId) {
this.deptId = deptId;
}
//重写hashCode和equals方法
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((commissionPct == null) ? 0 : commissionPct.hashCode());
result = prime * result + ((deptId == null) ? 0 : deptId.hashCode());
result = prime * result + ((empBirth == null) ? 0 : empBirth.hashCode());
result = prime * result + ((empGender == null) ? 0 : empGender.hashCode());
result = prime * result + ((empId == null) ? 0 : empId.hashCode());
result = prime * result + ((empName == null) ? 0 : empName.hashCode());
result = prime * result + ((empSalary == null) ? 0 : empSalary.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (commissionPct == null) {
if (other.commissionPct != null)
return false;
} else if (!commissionPct.equals(other.commissionPct))
return false;
if (deptId == null) {
if (other.deptId != null)
return false;
} else if (!deptId.equals(other.deptId))
return false;
if (empBirth == null) {
if (other.empBirth != null)
return false;
} else if (!empBirth.equals(other.empBirth))
return false;
if (empGender == null) {
if (other.empGender != null)
return false;
} else if (!empGender.equals(other.empGender))
return false;
if (empId == null) {
if (other.empId != null)
return false;
} else if (!empId.equals(other.empId))
return false;
if (empName == null) {
if (other.empName != null)
return false;
} else if (!empName.equals(other.empName))
return false;
if (empSalary == null) {
if (other.empSalary != null)
return false;
} else if (!empSalary.equals(other.empSalary))
return false;
return true;
}
//重写toString方法
@Override
public String toString() {
return "Employee [empId=" + empId + ", empName=" + empName + ", empGender=" + empGender + ", empSalary="
+ empSalary + ", empBirth=" + empBirth + ", commissionPct=" + commissionPct + ", deptId=" + deptId
+ "]";
}
}
注意:
解析ResultSet,将一条记录封装成为一个POJO对象:
List<Employee> empList = new LinkedList<Employee>();
Employee emp = null;
//[5]获取结果集中的数据,分析数据
while(set.next()) { //使用while循环负责遍历记录
//每一次while循环都得到一条数据库记录,我们的目的是将这一条记录包装成一个POJO对象
//set.getXXX()得到字段值 -> pojo.setXXX()赋给对应属性的set方法
emp = new Employee();
//装载POJO对象的过程就是获取一条记录中所有字段的过程
emp.setEmpId(set.getInt("emp_id")); //emp_id -> empId
emp.setEmpName(set.getString("emp_name")); //emp_name -> empName
emp.setEmpGender(set.getString("emp_gender")); //emp_gender -> empGender
emp.setEmpSalary(set.getDouble("emp_salary")); //emp_salary -> empSalary
emp.setEmpBirth(set.getDate("emp_birth")); //emp_birth -> empBirth
emp.setCommissionPct(set.getDouble("commission_pct")); //commission_pct -> commissionPct
emp.setDeptId(set.getInt("dept_id")); //dept_id -> deptId
empList.add(emp);
}
empList = new ArrayList<>(empList); //将善于增删的LinkedList转换位善于遍历的ArrayList
for (Employee employee : empList) {
System.out.println(employee);
}
关闭数据库连接资源的问题:
1.Connection、PreparedStatement、ResultSet对象之间的关系:
结论:
2.代码改进:
finally {
//[6]关闭结果集对象,关闭Statement对象,关闭连接对象
try {
if(conn != null) { //关闭Connection
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
1.静态代理模式
嘉靖皇帝,不上朝,不理政,除了吃喝玩乐,什么都不会
现在掌管朝政大权的是大臣严嵩
突然有一天,上来奏折,说南方有叛军起义,还有洪水泛滥,还有干旱,田地颗粒无收,现在已经天下大乱
嘉靖皇帝着急了……
皇帝现在不会理政,但是还要处理洪水问题、叛乱问题、干旱问题
于是乎皇帝找到严嵩老臣,向他请教……
严嵩说:咱们这么这么这么办……
皇帝说:OK,没毛病,下诏书!
问题:从明面上来说,治理天下的是谁?真正干活的是谁?
治理天下:皇帝
真正干活:严嵩(皇帝的代理核心)
有一天,皇帝说,我要娶媳妇!
宣布娶媳妇:皇帝
真正娶媳妇:皇帝
class 皇帝 {
严嵩 严嵩 = new 严嵩();
public void 治理叛军() {
严嵩.治理叛军();
}
public void 治理洪水() {
严嵩.治理洪水();
}
public void 治理干旱() {
严嵩.治理干旱();
}
public void 娶媳妇() {
皇帝自己娶媳妇;
}
}
上述设计模式就是静态代理模式:
皇帝不会的事情,都交给严嵩去做
也就是说在代理对象中,无法完成的方法,交给代理核心完成
在代理对象中,代理对象自己能够执行的方法,交给代理对象自己完成
连接池的构建:
连接池的主要功能:
/*
* 连接池的功能:
* 1.初始化连接池:
* 创建20个JDBC4Connection对象,将JDBC4Connection对象封装成MyConnection对象
* 封装成MyConnection对象之后,就能够保证在调用close()方法的时候是回收连接,而不是释放连接
* 将20个MyConnection对象放在freeConns集合当中,作为闲置连接等待调用
*
* 2.分配连接:
* 当有DAO执行方法申请连接对象的时候,为这个DAO方法分配MyConnection对象
* 如果freeConns中还有闲置连接,从这些闲置;连接中获取第一个(取栈顶元素)
* 交给DAO方法使用
* 将这个正在被占用的MyConnection对象加入activConns集合中,代表被占用
*
* 3.回收连接:
* 回收连接的方法非常简单,就是调用MyConnection中的close()方法即可
* 将当前被释放的连接从activeConns中删除
* 加入到freeConns集合中(元素入栈)
*/
初始化连接池:
//1.初始化连接池:
static {
try {
//[1.1]读取配置文件信息
Properties pro = new Properties();
InputStream is = ConnectionFactory.class.getResourceAsStream("/jdbc.properties");
pro.load(is);
jdbcDriver = pro.getProperty("jdbc.driver");
jdbcUrl = pro.getProperty("jdbc.url");
jdbcUsername = pro.getProperty("jdbc.username");
jdbcPassword = pro.getProperty("jdbc.password");
jdbcAutoCommit = pro.getProperty("jdbc.autocommit");
jdbcMaxConn = pro.getProperty("jdbc.maxconn");
jdbcTimeout = pro.getProperty("jdbc.timeout");
jdbcTryTime = pro.getProperty("jdbc.trytime");
//[1.2]注册驱动
Class.forName(jdbcDriver);
System.out.println("数据库驱动注册成功");
/*
* [1.3]通过DriverManager获取20个MySQL提供的JDBC4Connection对象,作为代理核心使用
* 将代理核心对象封装成MyConnection对象,加入freeConns集合
*/
for(int i = 0; i < Integer.parseInt(jdbcMaxConn); i++) {
//1.创建代理核心
Connection jdbc4conn = DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword);
jdbc4conn.setAutoCommit(Boolean.parseBoolean(jdbcAutoCommit));
//2.封装代理对象MyConnection对象
MyConnection mconn = new MyConnection(jdbc4conn);
//3.加入闲置连接集合
freeConns.push(mconn);
}
}catch(Exception e) {
e.printStackTrace();
System.out.println("数据库驱动注册失败");
}
}
分配连接:
//2.分配连接
public static Connection getConnection() {
Connection conn = null;
//[1]从闲置连接集合中选择一个闲置连接,出栈
if(!freeConns.isEmpty()) {
conn = freeConns.pop();
//[2]将这个出栈的连接对象加入占用连接集合
activConns.add(conn);
System.out.println("连接分配成功");
}else { //没有闲置连接
//如果没有得到连接对象,那就等待1000毫秒,再次重试
for(int i = 0; i < Integer.parseInt(jdbcTryTime); i++) {
try {
Thread.sleep(Integer.parseInt(jdbcTimeout));
} catch (InterruptedException e) {
e.printStackTrace();
}
if(!freeConns.isEmpty()) { //重新尝试获取连接
conn = freeConns.pop();
activConns.add(conn);
System.out.println("连接分配成功");
}
if(conn != null) { //尝试成功,获取对象
break;
}
}
//如果重试3次之后,还没有得到连接,直接返回null的conn对象
}
//[3]返回这个连接对象
if(conn == null) {
System.out.println("连接分配失败");
}
return conn;
}
回收连接:
//3.回收连接
@Override
public void close() throws SQLException {
//TODO:回收连接的方法
//只要更改这个close()方法即可,使得调用这个方法的时候不是销毁连接对象,而是将连接对象归还连接池
//[1]将被占用的连接释放
activConns.remove(this);
//[2]将这个连接加入空闲连接栈的栈顶
freeConns.push(this);
System.out.println("连接已释放");
}
使用连接池的方案:
创建一个常备的连接池,其中保持一定数量的常备连接,DAO需要访问数据库的时候,就从这个连接池中获取连接对象,用过之后不是释放连接,而是将这个连接对象返回给连接池,保证连接的重用,可以提高数据库的运行效率
连接对象的线程安全问题:
连接对象Connection本身是线程不安全的
如果两个线程公用同一个Connection对象,将会导致数据的不安全
解决方案:
为分配连接对象和连接对象所有的方法都加上同步锁
注意:
这会导致:
线程安全性问题的根源是什么:
解决方案:
问题:
initialValue():
提供第一次访问当前ThreadLocal的线程一个共享资源拷贝副本,一个protected修饰的方法,用来在子类继承ThreadLocal的时候进行重写
在默认情况下,initalValue()方法返回的默认值是null,如果将这个方法进行重写的话,可以用这个方法返回一个默认值。
get():
返回当前ThreadLocal中与当前线程绑定的一个共享资源的副本,在当前ThreadLocal对象中有一个共享资源的原本,当每次调用这个get()方法的时候,ThreadLocal会为调用这个get()的线程分配一个共享资源原本的拷贝版本,并将这个拷贝版本交给调用get()方法的线程,保存在线程的Map当中。
get()方法有一个前提,就是在ThreadLocal中已经存在一个与当前线程绑定的资源对象,如果一个线程第一次调用get()方法,将会返回一个null,如果一个ThreadLocal已经重写的initialValue()方法,那么此时将会返回initalValue()中声明的对象
set(T value):
将共享资源的副本和调用set()方法的线程进行绑定,如果共享资源的副本已经存在,但是尚且没有线程进行访问,副本处于未绑定状态,此时如果有线程进行访问,可以通过set方法将资源副本和调用set方法的线程进行绑定,绑定过程就是创建一个键值对,并且将这个键值对存入当前线程的Map中的过程。
**键:**ThreadLocal对象;**值:**和当期前线程绑定的资源副本
remove():
释放掉与当前线程相关的资源副本,在连接池中,资源副本就是Connection对象,释放资源副本,就相当于连接用完了,要放回闲置连接池当中
作用:
常见的数据源:
C3P0数据源的使用方式:
public class C3P0ConnectionPool {
private static ComboPooledDataSource cpds;
static {
try {
/*
* 在创建ComboPooledDataSource对象的时候,C3P0连接池会自动访问位于类路径下的文件名为c3p0.properties的那个文件
* 只要这个文件存在,C3P0连接池就会自动访问其中的数据库配置,不必手动加载
*/
cpds = new ComboPooledDataSource();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection conn = null;
try {
conn = cpds.getConnection();
conn.setAutoCommit(false);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
}
配置文件:
#驱动类路径
c3p0.driverClass=oracle.jdbc.driver.OracleDriver
#数据库访问地址URL
c3p0.jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl
#数据库用户名
c3p0.user=root
#数据库密码
c3p0.password=root
#连接池中保持常备连接的最大值
c3p0.maxPoolSize=20
#连接池中保持常备连接的最小值
c3p0.minPoolSize=5
#初始化连接池的时候,连接的数量,这个取值最好在minPoolSize和maxPoolSize之间取值
c3p0.initialPoolSize=5
#当连接池中常备连接耗尽之后,一次性增长多少连接
c3p0.acquireIncrement=5
#一个线程在无法获取闲置连接的情况下,能够重试的次数
c3p0.acquireRetryAttempts=30
#线程在无法获取闲置连接的时候,每次重试之间的时间间隔
c3p0.acquireRetryDelay=1000
使用场景:
一段代码中,可以分为n多段,其中:
那么我们就将两边的代码抽取出来,构建成为一个模板方法,在这个模板方法中插入什么样的内容,执行的就是什么方法,策略模式适用于两端代码可以重用,中间代码可以动态替换的地方
模板类型:
public class DAOTemplate<T> {
/**
* 执行查询方法的模板
*/
public List<T> selectTemplate(SelectExecutor exe) {
Connection conn = null;
List<T> resultList = null;
try {
conn = C3P0ConnectionPool.getConnection();
//----------从这一句向上,都是模板的上半部分----------
//----------中间插入动态替换的SQL执行过程
resultList = exe.execute(conn);
//----------从这一句向下,都是模板的下半部分----------
}catch(Exception e) {
e.printStackTrace();
}finally {
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return resultList;
}
/**
* 执行增删改方法的模板
*/
public int updateTemplate(UpdateExecutor exe) {
Connection conn = null;
int result = 0;
try {
conn = C3P0ConnectionPool.getConnection();
//----------从这一句向上,都是模板的上半部分----------
//----------中间插入动态替换的SQL执行过程
result = exe.execute(conn);
//----------从这一句向下,都是模板的下半部分----------
conn.commit();
}catch(Exception e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return result;
}
}
执行器类:
public interface SelectExecutor<T> {
public List<T> execute(Connection conn) throws Exception;
}
public interface UpdateExecutor {
public int execute(Connection conn) throws Exception;
}
使用策略模式实现的DAO类型:
作用:
public class EmployeeDAOImpl implements EmployeeDAO {
private DAOTemplate<Employee> template = new DAOTemplate<>();
@Override
public List<Employee> selectAllEmployee() {
SelectExecutor<Employee> exe = new SelectExecutor<Employee>() {
@Override
public List<Employee> execute(Connection conn) throws Exception {
PreparedStatement stat = null;
ResultSet set = null;
List<Employee> empList = new ArrayList<Employee>();
//[3]编写SQL,预编译PreparedStatement
String sql = "select * from employees";
stat = conn.prepareStatement(sql);
//[4]执行SQL,得到结果集
set = stat.executeQuery();
//[5]分析结果集,得到数据
Employee emp = null;
while(set.next()) { //从数据库记录 -> pojo对象
emp = new Employee();
emp.setEmpId(set.getInt("emp_id"));
emp.setEmpName(set.getString("emp_name"));
emp.setEmpGender(set.getString("emp_gender"));
emp.setEmpSalary(set.getDouble("emp_salary"));
emp.setEmpBirth(set.getDate("emp_birth"));
emp.setCommissionPct(set.getDouble("commission_pct"));
emp.setDeptId(set.getInt("dept_id"));
empList.add(emp);
}
return empList;
}
};
return template.selectTemplate(exe);
}
@Override
public Employee selectEmployeeById(Integer empId) {
List<Employee> list = template.selectTemplate(new SelectExecutor<Employee>() {
@Override
public List<Employee> execute(Connection conn) throws Exception {
PreparedStatement stat = null;
ResultSet set = null;
List<Employee> empList = new LinkedList<Employee>();
//[3]编写SQL,预编译PreparedStatement
String sql = "select * from employees where emp_id = ?";
stat = conn.prepareStatement(sql);
//[4]执行SQL,得到结果集
stat.setInt(1, empId);
set = stat.executeQuery(); //ResultSet中只有1条记录
//[5]分析结果集,得到数据
Employee emp = null;
if(set.first()) { //如果当前结果集当中存在至少一条记录,那么set.first()将会返回true,并且将记录的位指针指向第一条记录
emp = new Employee();
emp.setEmpId(set.getInt("emp_id"));
emp.setEmpName(set.getString("emp_name"));
emp.setEmpGender(set.getString("emp_gender"));
emp.setEmpSalary(set.getDouble("emp_salary"));
emp.setEmpBirth(set.getDate("emp_birth"));
emp.setCommissionPct(set.getDouble("commission_pct"));
emp.setDeptId(set.getInt("dept_id"));
empList.add(emp);
}
return empList;
}
});
return list.get(0);
}
@Override
public Integer insertEmployee(Employee emp) {
return template.updateTemplate(new UpdateExecutor() {
@Override
public int execute(Connection conn) throws Exception {
PreparedStatement stat = null;
int result = 0; //代表当前增删改方法影响的行数
//对于增删改操作来讲,我们需要开启事务,提交事务,如果遇见异常,我们还要回滚事务
//[3]编写SQL,预编译
String sql = "insert into Employees "
+ "(emp_name, emp_gender, emp_salary, emp_birth, commission_pct, dept_id) "
+ "values (?, ?, ?, ?, ?, ?)";
stat = conn.prepareStatement(sql);
//[4]设定参数,执行SQL,得到结果影响行数:pojo对象 -> 数据库记录
stat.setString(1, emp.getEmpName());
stat.setString(2, emp.getEmpGender());
stat.setDouble(3, emp.getEmpSalary());
stat.setDate(4, emp.getEmpBirth());
stat.setDouble(5, emp.getCommissionPct());
stat.setInt(6, emp.getDeptId());
result = stat.executeUpdate();
//[5]分析影响行数
return result;
}
});
}
@Override
public Integer deleteEmployeeById(Integer empId) {
return template.updateTemplate(new UpdateExecutor() {
@Override
public int execute(Connection conn) throws Exception {
PreparedStatement stat = null;
int result = 0;
String sql = "delete from Employees where emp_id = ?";
stat = conn.prepareStatement(sql);
stat.setInt(1, empId);
result = stat.executeUpdate();
return result;
}
});
}
@Override
public Integer updateEmployeeById(Employee emp) {
return template.updateTemplate(new UpdateExecutor() {
@Override
public int execute(Connection conn) throws Exception {
PreparedStatement stat = null;
int result = 0;
String sql = "update Employees set emp_name = ?, emp_gender = ?, emp_salary = ?, emp_birth = ?, "
+ "commission_pct = ?, dept_id = ? where emp_id = ?";
stat = conn.prepareStatement(sql);
stat.setString(1, emp.getEmpName());
stat.setString(2, emp.getEmpGender());
stat.setDouble(3, emp.getEmpSalary());
stat.setDate(4, emp.getEmpBirth());
stat.setDouble(5, emp.getCommissionPct());
stat.setInt(6, emp.getDeptId());
stat.setInt(7, emp.getEmpId());
stat.executeUpdate();
return result;
}
});
}
}