DAO层 ---- 数据库
Javaweb — DAO 116天
DAO层和module层
或许感觉有点杂乱,但是也不杂乱,因为昨天分享了一下应用的分层,底层是DAO层调用的数据库;而不是直接用Action或者Service来操作数据库;昨天的单表操作是因为这个程序过于简单,所以就没有分层
数据库中每一张表都关联一个实体类接口和实现类,一个Dao接口和Dao实现类
DAO【mapper】
DAO database access object 数据库访问对象
作用就是 数据库访问对象在开发时提供针对某张表的操作细节【一张表就对应一个DAO】CRUD
优点就是: 在管理系统开发时,通过数据访问对象可以避免反复的SQL命令书写;
在管理系统开发时,通过数据库访问对象可以避免反复的JDBC开发步骤书写----昨天的程序中虽然有了DBUtil,但是还是出现了大量的重复的JDBC编程六步
DAO类就是提供数据库访问对象的类
DAO类开发规则
- 一个DAO类封装的时一张表的操作细节【每一张表对应一个DAO类】
- DAO类命名的规则是:表名 + DAO 比如封装student表-----》StudentDao
- DAO类所在包的命名规则:com.cfeng.DAO 所有的DAO类都在这个包中
DAO类实例:StudentDao
这里就知道为什么是一张表对应一个Dao了,因为每一张表的结构不同,参数不同;传入的参数和可能修改的位置都不同,而对于某一张表,其传入的参数的个数都是固定的;比如昨天的学生表,就三个参数;所以将这三个参数直接封装成为一个增的方法;然后删除和修改都是按照主键进行的操作,所以参数就是主键stuno
package cfeng.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import cfeng.utils.DBUtil;
public class StudentDao {
//增加数据行;返回的是插入数据的行数
public int addStudent(String stuno,String stuname,String stuclass) {
Connection conn = null;
PreparedStatement state = null;
int count = 0;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false);
String sql = "INSERT INTO student (stuno,stuname,stuclass) VALUES (?,?,?)";
state = conn.prepareStatement(sql);
state.setString(1, stuno);
state.setString(2, stuname);
state.setString(3, stuclass);
count = state.executeUpdate();
conn.commit();
} catch (SQLException e) {
if(conn != null) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
}finally {
DBUtil.close(conn, state, null);
}
return count;
}
//修改数据行
public int editModifyStudent(String stuno,String stuname,String stuclass) {
Connection conn = null;
PreparedStatement state = null;
int count = 0;
try {
conn = DBUtil.getConnection();
conn.setAutoCommit(false);
String sql = "UPDATE student SET stuname = ?,stuclass=? WHRER stuno =" + stuno;
state = conn.prepareStatement(sql);
state.setString(1, stuname);
state.setString(2, stuclass);
count = state.executeUpdate();
//提交事务
} catch (SQLException e) {
if(conn != null) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
}finally {
DBUtil.close(conn, state, null);
}
return count;
}
//还有查找,删除就类似写完就可
}
那么我们之前在写AddAction的时候就可以调用DAO层的操作完成简单的书写即可
package cfeng.oa.actions;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class StudentAddAction extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取数据,解决中文乱码
req.setCharacterEncoding("UTF-8");
String stuno = req.getParameter("stuno");
String stuname = req.getParameter("stuname");
String stuclass = req.getParameter("stuclass");
// System.out.println(stuno + stuname + stuclass); 测试是否传入成功
//连接数据库,操作数据库
Dao studentDao = new StudentDao(); //这里要使用单例模式,并且严格分层还不能new对象
int count = studentDao.addStudent(stuno,stuname,stuclass);
//根据方法返回值来判断
if(count == 1) {
//success
resp.sendRedirect(req.getContextPath() + "/student/list");
}else {
//添加失败
}
}
}
这样就可以简化代码,因为大量重复的代码,可能会影响后期的调试的效率;原本几十行的代码被封装到DAO数据库访问对象;这样就简单两行代码就取代了之前的很多的代码
查询操作的问题?
上面的是增删改,都很简单,就操作即可;那么对于查询怎么操作呢,查询需要返回一个查询结果集,比如最开始的index.html点击就是查询的数据库,将结果集返回插入表中
//查询,按照学号查询;不用事务,不会修改表
public ResultSet GetStudent(String stuno) {
Connection conn = null;
PreparedStatement state = null;
ResultSet result = null;
try {
conn = DBUtil.getConnection();
String sql = "SELECT stuno,stuname,stuclass FROM student WHERE stuno= ?";
state = conn.prepareStatement(sql);
state.setString(1, stuno); //注意State才是拼接sql,而PreparedState是预编译,都是?通配
result = state.executeQuery();
//处理查询结果集
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(conn, state, result);
}
return result; //这里上面的finally已经将result给关闭了,返回的是null
}
查询的过程中就有了问题,上面的处理查询结果集,就是想将查询结果集给返回,但是上面关闭了,怎么办?难道不关闭,不可以,因为这是规范,必须要释放资源
那就必须有一个变量来接收这个结果集,什么变量呢? 首先结果集里面是什么?是表中的字段,这些字段就是对应的一个类的属性,比如一个student类,它的属性有stuno,stuname,stuclass;这就是成员变量,定义为私有即可
实体类model层 【Entity,domain】
- 实体类就是实体的软件建模,一个实体类描述一张表结构【这是学习数据库之后的思维转换】,实体类的创建也应该有接口和实现类;面向接口编程
- 实体类的类名应该和关联的表名保持一致,可以忽略大小写 比如student表对应的实体的实现类就是Student
Student.frm ----------------> public class Student(){
stuno INT private int stuno;
stuname VARCHAR(255) private String stuname;
stuclass VARCHAR(255) private String stuclass;
}
- 实体类中的一个实例对象用于在内存中存储对应的表文件中一个数据行
比如 表中的数据 1 张三 HC2001 -----> Student student = new Student(1,"张三","HC2001");
那么现在就建立一个实体类Student类接收这个表中的数据【其实实际的过程就是产生了实体,同时分析和建立数据库表】
//直接使用快捷键创建构造器和set和get方法
package cfeng.entity;
/**
* @author OMEY-PC student表的实体,可以承载表的查询结果集
*/
public class Student {
private int stuno;
private String stuname;
private String stuclass;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(int stuno, String stuname, String stuclass) {
super();
this.stuno = stuno;
this.stuname = stuname;
this.stuclass = stuclass;
}
public int getStuno() {
return stuno;
}
public void setStuno(int stuno) {
this.stuno = stuno;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public String getStuclass() {
return stuclass;
}
public void setStuclass(String stuclass) {
this.stuclass = stuclass;
}
}
那么查询出来的一行结果就是一个实例对象
//查询,按照学号查询;不用事务,不会修改表 -- 查询所有
public List GetStudent() {
Connection conn = null;
PreparedStatement state = null;
ResultSet result = null;
List list = new ArrayList<Student>();
try {
conn = DBUtil.getConnection();
String sql = "SELECT stuno,stuname,stuclass FROM student";// WHERE stuno= ?
state = conn.prepareStatement(sql);
// state.setString(1, stuno); //注意State才是拼接sql,而PreparedState是预编译,都是?通配
result = state.executeQuery();
//处理查询结果集
//将查询结果创建为实体对象返回,但是这里是结果集,所以使用容器接收
while(result.next()) {
int no = Integer.valueOf(result.getString("stuno"));
String name = result.getString("stuname");
String stuclass = result.getString("stuclass");
Student student = new Student(no,name,stuclass);
//将对象给放进去
list.add(student);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(conn, state, result);
}
return list; //这里上面的finally已经将result给关闭了,返回的是null
}
将对象放到集合中返回就可以了,这样查询操作就完成
现在可以测试一下查询的效果
package cfeng.oa.actions;
import java.util.List;
import cfeng.oa.dao.StudentDao;
import cfeng.oa.entity.Student;
public class Test {
public static void main(String[] args) {
//测试DAO的查询功能
StudentDao stuDao = new StudentDao();
List<Student> list = stuDao.GetStudent();
for(Student s:list) {
System.out.println(s.getStuno() + " : " + s.getStuname() + " : " + s.getStuclass());
}
}
}
1 : 张三 : HC2001
2 : 李四 : HC2002
3 : Cfeng : HC2002
4 : 王五 : HC2001
6 : Jning : HC2001
7 : 里斯 : HC2003
8 : 卡夫卡 : HC2004
9 : 里仁 : HC2003
所以开发主要是要层次化开发,这个小小的编程实例,其实也可以分成多层来进行开发,这里可以分为entity实体层【model】;数据库访问层Dao,这两层就是项目初期分析的时候设计数据库表,分析实体;之后还应该有service层和view层的;但是这里就简单使用了action层,收转功能;控制层的,直接和页面进行交互
之前写程序的时候,没有使用Dao,导致action的开发异常繁杂,主要就是JDBC的编程规范,将JDBC操作封装到Dao中之后业务开发就简化了许多。