在实际开发中,将增删改查的代码操作执行在客户端上是不好的,这样会使代码重复度变高,不利于维护.
为了降低耦合性,提出了DAO (Data Access Object) 封装数据库操作的设计模式。
这种设计使得业务逻辑和数据库操作相分离,DAO组件依赖于数据库系统,在不暴露具体操作的情况下给出了各种对数据库访问的接口,体现了很强的抽象封装思想.
例如我要做一个mysql查询
我会有
数据javabean类
Student
:用于封装学生信息
DAO接口
IStudentDAO
:写出增删改查操作的接口
DAO接口实现类
StudentDAOImpl
:实现接口sql操作细节
测试类
StudentDAOTest
:输入操作,简单模拟客户端功能
依次代码如下
package domain;
import lombok.Getter;
import lombok.Setter;
//学生信息对象
@Getter
@Setter
public class Student {
private Long id;
private String name; //姓名
private int age; //年龄
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
package dao;
import java.util.List;
import domain.Student;
//封装Student对象的CRUD操作
public interface IStudentDAO {
/**
* 保存操作
* @param stu 学生对象,封装了需要保存的信息
*/
void save(Student stu);
/**
* 删除操作
* @param id 被删除学生信息的id
*/
void delete(Long id);
/**
* 更新操作
* @param id 被更改学生的主键值
* @param newstu 学生新的信息
*/
void update(Long id, Student newStu);
/**
* 查询操作
* @param id 查询学生信息的id
* @return 如果id存在,返回该学生对象,否则返回null
*/
Student get(Long id);
/**
* 查询并返回所有学生对象
* @return 如果结果集为空(表中没数据),返回一个空的List对象
*/
List ListAll();
}
package dao.impl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.List;
import dao.IStudentDAO;
import domain.Student;
public class StudentDAOImpl implements IStudentDAO {
public void save(Student stu) {
}
public void delete(Long id) {
}
public void update(Long id, Student newStu) {
}
public Student get(Long id) {
String sql = "SELECT * FROM t_student WHERE id = " + id;
//声明资源对象
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
//1.加载sql驱动
Class.forName("com.mysql.jdbc.Driver");
//2.创建连接对象
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "admin");
//3.创建语句对象
st = conn.createStatement();
//4.执行sql
rs = st.executeQuery(sql);
//----------------
//处理结果集rs
if (rs.next()) {
Student stu = new Student();
//获取当前结果集光标所指行的指定列的值
stu.setId(rs.getLong("id"));
stu.setName(rs.getString("name"));
stu.setAge(rs.getInt("age"));
return stu;
}
//----------------
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.释放资源
try {
if (rs != null) {
rs.close();
}
} catch (Exception e2) {
} finally {
try {
if (st != null) {
st.close();
}
} catch (Exception e3) {
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (Exception e4) {
}
}
}
}
return null;
}
public List ListAll() {
return null;
}
}
package test;
import org.junit.Test;
import dao.IStudentDAO;
import dao.impl.StudentDAOImpl;
import domain.Student;
public class StudentDAOTest {
//依赖DAO对象
private IStudentDAO studentDAO = new StudentDAOImpl();
@Test
public void testSave() {
}
@Test
public void testDelete() {
}
@Test
public void testUpdate() {
}
@Test
public void testGet() {
Student stu = studentDAO.get(1L);
System.out.println(stu);
}
@Test
public void testListAll() {
}
}
查询结果
上述代码如果写完所有功能后明显是有很多明显冗余的
要改进代码比如以下几点
1.将代码重构,提取并封装重复代码,比如加载sql驱动包,创建连接对象,释放资源等等,可提取出一个jdbcUtils类
2.将数据库配置信息提取出一个db.preperties避免硬编码
3.使用PreparedStatement接口代替Statement接口,用来减少sql语句拼写容易出错的问题
4.提出数据库连接池的概念,用来处理[ 多次创建并关闭connection以至于成本太大 ]的问题
5.CRUD操作可以封装到jdbcTemplate类中,创建一套标准操作模板
6.模拟Hibernate框架简化编写sql,直接操作数据库
什么是事务:
事务在数据库中指"一组逻辑操作",不论成功和失败都作为一个整体执行,要么全执行,要么全不执行
以防异常操作
比如生活中在某两个sql操作之间停电,执行了一个但是没执行下一个这样业务逻辑就会出错
处理事务的两个动作:
提交(commit):当整个事务中,所有的逻辑操作都正常执行成功 --->提交事务
回滚(rollback):当整个事务中,有一个或者多个逻辑操作执行失败 --->回滚事务,撤销该事务中所有操作
事务的ACID属性:
1.原子性(Atomicity):事务应该是应用中的最小单元,要么全部执行,要么都不执行.
2.一致性(Consistency):事务结束后,数据库内的数据是合法的(数据不会破坏).
3.隔离性(Isolation):并发执行的事务之间相互独立,互不干扰.
4.持久性(Durability):事务提交后,数据是永久性的,不可回滚.
处理方法:
Connection对象.setAutoCommit(false);
try{
sql系列操作
Connection对象.commit();//提交事务
}catch(Exception e){
Connection对象.rollback();//回滚事务
}finally{
//释放资源
}