Dao模式
程序员写的是业务(因为其逻辑性不太强)
软件设计原则:开闭原则,对新增加的进行开放,对修改关闭
实际开发中, web项目, 程序员编写业务代码
把所有的代码都写在业务方法中:
接收前端请求,获取请求参数...
编写业务代码处理请求
调用jdbc代码操作数据
把数据进行加工
把数据响应给前端
缺点:
方法很臃肿, 这个方法不便于复用, 部分重复代码重复写
方法的扩展性不好, 因为代码全部集中在一个方法内部, 替换某部分的代码,对这个方法进行修改
解决方案: 拆的思想
把方法拆分为多个方法, 不是OOP编程思想
把方法拆分为多个方法,把这个方法分类, 把不同功能的方法放在不同的类, 不同层次的类在进行分层(包)
常见的分层:
操作数据库的层: DAO层(数据访问层)
业务处理的层: service层(业务层)
表对应实体类层: 实体层(entity,pojo)
工具类存放的层: 工具层(util)
处理前端请求层: web层
分层的目的:
使用层来技术隔离, 方便每一层的技术替换,而不需要修改其他层
使用层来进行解耦, 每一层直接的调用, 以接口的形式
- 上下层之分, 上层调用下层,不能下层调用上层,不能跨层调用
使用dao模式开发:
-
编写实体类, 与数据库的表一一对应
类与表对应
一行记录对应类的一个对象
表的字段对应类的属性
数据库的数据类型与java的数据类型对应 java推荐使用包装类型
mysql java int Integer/int bigint Long/long double Double/double decimal java.math.BigDecimal /Double char/varchar/text String date/datetime/time/timestamp java.util.Date tinyint Integer/int/Boolean
、
package com.fs.soso.entity;
推荐使用
/**
* 对应tb_card表的实体类
*/
public class Card {
private Integer id;
private String cardNumber;
private Integer status;
//get/set toString
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Card{" +
"id=" + id +
", cardNumber='" + cardNumber + '\'' +
", status=" + status +
'}';
}
public Card() {
}
public Card(Integer id, String cardNumber, Integer status) {
this.id = id;
this.cardNumber = cardNumber;
this.status = status;
}
public Card(String cardNumber, Integer status) {
this.cardNumber = cardNumber;
this.status = status;
}
}
-
编写dao接口,以及dao接口的实现类
实体类--> 实体类dao接口 --> 实体类dao实现类--> 实体类业务接口 --> 实体类业务接口实现类
Card --> [I]CardDao --> CardDaoImpl --> [I]CardService--> CardServiceImpl
package com.fs.soso.dao; import com.fs.soso.entity.Card; import java.util.List; /** * 卡的数据访问接口 * CURD */ public interface CardDao { /** * 添加记录 * @param card 手机卡对象 * @return 受影响行数 */ int add(Card card); /** * 根据主键修改 * @param card 手机卡对象 * @return 受影响行数 */ int updateById(Card card); /** * 根据主键删除 * @param id 主键值 * @return 受影响行数 */ int deleteById(int id); /** * 根据主键查询 * @param id 主键 * @return 手机卡对象 */ Card queryById(int id); /** * 查询所有 * @return 手机卡List集合 */ List<Card> queryAll(); }
package com.fs.soso.dao.impl;
import com.fs.soso.dao.CardDao;
import com.fs.soso.entity.Card;
import com.fs.soso.util.JdbcUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class CardDaoImpl implements CardDao {
@Override
public int add(Card card) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = JdbcUtil.getConnection();
String sql ="insert into tb_card(cardNumber,status) values(?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setObject(1,card.getCardNumber());
pstmt.setObject(2,card.getStatus());
return pstmt.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtil.close(conn,pstmt,null);
}
return 0;
}
@Override
public int updateById(Card card) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = JdbcUtil.getConnection();
String sql ="update tb_card set status = ? where id = ? ";
pstmt = conn.prepareStatement(sql);
pstmt.setObject(1,card.getStatus());
pstmt.setObject(2,card.getId());
return pstmt.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtil.close(conn,pstmt,null);
}
return 0;
}
@Override
public int deleteById(int id) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = JdbcUtil.getConnection();
String sql ="delete from tb_card where id = ? ";
pstmt = conn.prepareStatement(sql);
pstmt.setObject(1,id);
return pstmt.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtil.close(conn,pstmt,null);
}
return 0;
}
@Override
public Card queryById(int id) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet resultSet = null;
try {
conn = JdbcUtil.getConnection();
String sql ="select * from tb_card where id = ? ";
pstmt = conn.prepareStatement(sql);
pstmt.setObject(1,id);
resultSet = pstmt.executeQuery();
Card card=null;
while(resultSet.next()){
card = new Card();
//给属性赋值
//getXxx(int 列的序号从1开始)
//getXxx(String 列名) 可读性高
card.setId(resultSet.getInt("id"));
card.setCardNumber(resultSet.getString("cardNumber"));
card.setStatus(resultSet.getInt("status"));
}
return card;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtil.close(conn,pstmt,null);
}
return null;
}
@Override
public List<Card> queryAll() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet resultSet = null;
try {
conn = JdbcUtil.getConnection();
String sql ="select * from tb_card";
pstmt = conn.prepareStatement(sql);
resultSet = pstmt.executeQuery();
List<Card> cards = new ArrayList<>();
while(resultSet.next()){
Card card = new Card();
//给属性赋值
card.setId(resultSet.getInt("id"));
card.setCardNumber(resultSet.getString("cardNumber"));
card.setStatus(resultSet.getInt("status"));
//把对象添加到集合中
cards.add(card);
}
return cards;
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtil.close(conn,pstmt,null);
}
return null;
}
}
junit进行单元测试(必须掌握)
对编写方法进行测试, 实际开发中,使用junit进行单元测试
使用步骤:
- 导入junit依赖
2.创建存放测试源代码的资源目录
项目完成之后, 删除测试代码
创建存放测试代码的资源目录 test
- 根据被测试的类(接口),生成对应的测试类
- 编写测试代码
package com.fs.soso.dao; import com.fs.soso.dao.impl.CardDaoImpl; import com.fs.soso.entity.Card; import org.junit.After; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; public class CardDaoTest { private CardDao cardDao; /** * setUp() 使用 before修饰的, 表示该方法在调用测试方法之前执行 * 做准备工作 * @throws Exception */ @Before public void setUp() throws Exception { //System.out.println("setUp..."); cardDao = new CardDaoImpl(); } /** * tearDown() 使用 After修饰的, 表示该方法在调用测试方法之后执行 * 释放资源 * @throws Exception */ @After public void tearDown() throws Exception { //System.out.println("tearDown..."); } /** * @Test 标记方法上,表示这个方法是一个测试方法 * 直接运行测试方法,不需要main调用 * 测试方法要求: * 1. 返回值类型只能是void * 2. 一定是无参方法 * 3.不能是static修饰 */ @Test public void add() { //System.out.println("add..."); Card card = new Card("16666666666",0); int rs = cardDao.add(card); System.out.println(rs); } @Test public void updateById() { Card card = new Card(12,"16666666666",1); cardDao.updateById(card); } @Test public void deleteById() { } @Test public void queryById() { System.out.println(cardDao.queryById(12)); } @Test public void queryAll() { System.out.println(cardDao.queryAll()); } }
使用commons-dbutil简化jdbc
commons-dbutil是apache开源组织提供的封装jdbc的工具包
使用步骤:
- 导入commons-dbutil的jar
- 使用核心类, QueryRunner 执行增删改查的操作
结果集处理器:
BeanHandler: 把ResultSet转换为java实体对象
BeanListHandler: 把把ResultSet转换为List集合<java对象>
查询
增删改:
事务
jdbc的Connection默认是自动提交, 设置Connection为手动提交:
setAutoCommit(false); 手动提交
提交事务:
回滚事务:
事务概念: 面试重点
在同一个事务下,一组sql语句, 要就全部成功, 要就全部失败
事务的四大特征: ACID
嗖嗖移动大厅
1. 登录 业务流程
选择登录菜单
用户输入手机号码,密码
调用Dao层的方法,到数据库进行查询:
判断是否存在手机号码,密码记录, 如果存在, 判断是否被禁用
如果存在并且没有禁用, 登录成功, 显示二级菜单
否则,登录失败, 显示一级菜单