高效掌握JDBC技术| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤
Posted 微凉秋意
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高效掌握JDBC技术| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤相关的知识,希望对你有一定的参考价值。
文章目录
1、三层架构
- 一种合理的项目分层理念,好处为可以简化设计、各司其职、更容易扩展内容
- 三层架构分为:
- 表示层(UI、WEB):跟用户对接
- 业务逻辑层(service):书写功能的整体逻辑
- 数据访问层(dao):对接数据库
1.1、数据访问层
- DAO:和数据库交接、内存放着对数据库内容增删改查的方法
1.2、业务逻辑层
- Service:存放着代表主要功能的方法,内部内容主要为调用DAO+逻辑控制代码
1.2.1、组成
Service接口:
- 一张表对应一个Service
- Service中存放着与该表相关的所有功能方法
- 命名与表名相关:PersonService
- 包:须存放在service包下 com.xxx.service
Service实现类:
- 一个实现类实现一个service接口
- 命名为接口名+Impl:PersonServiceImpl
- 包:须存放在service.impl下 com.xxx.service.impl
1.3、表示层
- view:负责跟用户对接
1.3.1、实现
- 一个功能一个视图类
- 命名:功能+View
- 包:须放在view包下 com.xxx.view
- 内容:调用service+Scanner
1.4、完整实现步骤
-
书写实体类
package com.bz.entity; import java.io.Serializable; public class User implements Serializable private Integer id; private String username; private String pwd; @Override public String toString() return "User" + "id=" + id + ", username='" + username + '\\'' + ", pwd='" + pwd + '\\'' + ''; public User(Integer id, String username, String pwd) this.id = id; this.username = username; this.pwd = pwd;
-
书写DAO
package com.bz.dao; import com.bz.entity.User; /** * 跟数据库对接:从数据库中查找user信息 */ public interface UserDao /** * 查询用户信息是否存在 * @param username 用户名 * @param pwd 密码 * @return 用户对象 */ User selectUser(String username,String pwd) throws Exception;
-
书写DaoImpl
package com.bz.dao.impl; import com.bz.dao.UserDao; import com.bz.entity.User; import com.bz.util.JDBCUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; public class UserDaoImpl implements UserDao @Override public User selectUser(String username, String pwd) throws Exception User user=null;//用来返回 Connection conn= JDBCUtils.getConnection(); String sql = "select * from t_user where u_username=? and u_pwd=?"; PreparedStatement ps=conn.prepareStatement(sql); ps.setString(1,username); ps.setString(2, pwd); ResultSet rs=ps.executeQuery(); if (rs.next()) Integer id = rs.getInt("u_id"); String name = rs.getString("u_username"); String password = rs.getString("u_pwd"); user = new User(id, name, password); JDBCUtils.close(rs,ps,conn); return user;
-
书写Service
package com.bz.service; public interface UserService /** * 用户登录 * @param username 用户输入的账号名 * @param pwd 用户输入的密码 * @return 是否登录成功 */ boolean login(String username,String pwd) throws Exception;
-
书写ServiceImpl
package com.bz.service.impl; import com.bz.dao.UserDao; import com.bz.dao.impl.UserDaoImpl; import com.bz.service.UserService; public class UserServiceImpl implements UserService //创建Dao对象 private UserDao ud=new UserDaoImpl(); @Override public boolean login(String username, String pwd)throws Exception if (ud.selectUser(username, pwd)!=null) return true; else return false;
-
书写view
package com.bz.view; import com.bz.service.UserService; import com.bz.service.impl.UserServiceImpl; import java.util.Scanner; /** * 用户登录 */ public class UserloginTest public static void main(String[] args) throws Exception UserService us=new UserServiceImpl(); Scanner sc = new Scanner(System.in); System.out.println("请输入用户名:"); String username=sc.next(); System.out.println("请输入密码:"); String pwd=sc.next(); //调用Service方法判断登录是否成功 if (us.login(username,pwd)) System.out.println("登录成功!"); else System.out.println("登录失败");
2、事务及JDBCUtils最终版
-
回顾事务概念:将多个操作步骤归为同一个原子操作,要么同时成功,要么同时失败
开启事务
执行操作
结束事务:commit rollback
-
通常需要添加在Service层,Service层的所有功能方法都应该配套事务
2.1、事务基本操作与问题解决
- 开启事务:
Connection对象.setAutoCommit(false)
- 结束事务:
- 提交:
Connection对象.commit();
- 回滚:
Connection对象.rollback();
- 提交:
2.1.1、存在问题
操作事务和操作数据库数据的数据库连接不是同一个,或导致事务回滚不会影响数据库内容
2.1.2、解决方案:ThreadLocal
-
思路: 放入线程的存储空间中,
Service
和DAO
不再自行创建conn
,如有需要,直接从线程存储空间中取出 -
实现:
-
确保工具类只会创建一个
conn
对象 -
使用
ThreadLocal
将工具类创建的conn对象放入存储空间ThreadLocal:可以操作线程存储空间的工具,可以对空间的数据进行添加、获取、删除
添加:ThreadLocal对象.set(数据)
获取:ThreadLocal对象.get()
删除:ThreadLocal对象.remove()
-
-
使用:
- 由于DAO和Service共用同一个conn,并且Service一定晚于DAO执行结束,所以为了确保Service的执行,DAO中不能关闭conn,该操作应由Service完成
2.2、JDBCUtils-最终版
package com.bz.util;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
* 工具类:方便方法调用,所有方法都应为静态方法
*/
public class JDBCUtils
//提升集合的作用范围,确保getConnection方法中也能使用
private static Properties p=null;
//创建操作线程存储空间的工具对象
private static ThreadLocal<Connection> tl=new ThreadLocal<>();
//把流对象的创建放入静态初始代码块,确保在工具类类加载时执行
static
try(
//通过类对象.getResourseAsStream()获取一个字节输入流对象
//当前配置文件在src之下
InputStream is=JDBCUtils.class.getResourceAsStream("/jdbc.properties");
)
//创建用来接收的Properties集合
p=new Properties();
//调用方法加载配置文件的内容至集合中
p.load(is);
//1. 加载驱动
Class.forName(p.getProperty("driverClassName"));
catch (ClassNotFoundException e)
System.out.println("驱动路径不正确");
catch (Exception e)
e.printStackTrace();
/**
* 获取Connection连接
* @return
*/
public static Connection getConnection()
Connection conn =tl.get();
try
if (conn==null) //这里如果线程存储空间里没有conn就创建conn并存入线程空间
//2. 获取连接
//连接的url
String url = p.getProperty("url");
//用户名
String username = p.getProperty("username");
//密码
String pwd = p.getProperty("password");
conn = DriverManager.getConnection(url, username, pwd);
//将新创建的conn放入线程的存储空间
tl.set(conn);
catch (SQLException e)
System.out.println("获取连接失败");
catch (Exception e)
System.out.println("未知异常");
e.printStackTrace();
return conn;
/**
* 关闭资源连接 非空判断:防止空指针
* @param rs
* @param ps
* @param conn
*/
public static void close(ResultSet rs, PreparedStatement ps,Connection conn)
if (rs!=null)
try
rs.close();
catch (SQLException e)
System.out.println("关闭rs失败");
if (ps!=null)
try
ps.close();
catch (SQLException e)
System.out.println("关闭ps失败");
if (conn!=null)
try
conn.close();
catch (SQLException e)
System.out.println("关闭conn失败");
3、JUnit测试框架
- 作用:DAO层和Service层中的方法通常需要经过测试,
JUnit
可以通过@Test
注解完成执行测试,大大减少测试成本
3.1、使用步骤
-
导入
jar
包:-
hamcrest-core-1.3.jar
-
junit-4.12.jar
-
-
创建测试类
- 命名:被测试的类/接口+Test
- 包:须放在test包下
-
使用
- @Test注解必须写在方法上方
- 方法必须为公开、非静态、无参、无返回值的最普通的普通方法
- 一个测试方法中只能测试一个方法
- 通常情况下,测试方法名应与被测试方法一致,目的更为清晰
3.2、使用示例
package com.bz.test;
import com.bz.dao.AccountDao;
import com.bz.dao.impl.AccountDaoImpl;
import com.bz.entity.Account;
import org.junit.Test;
public class AccountDaoImplTest
//创建被测试的对象
AccountDao ad=new AccountDaoImpl();
@Test
public void selectAccountByName()
Account a = ad.selectAccountByName("张三");
System.out.println(a);
@Test
public void updateAccountByName()
int n = ad.updateAccountByName("张三", 100);
System.out.println(n);
4、JDBC项目开发步骤总结
首先要根据要求来建库建表(数据库的内部操作)
-
导入jar包:
hamcrest-core-1.3.jar
junit-4.12.jar
mysql-connector-java-8.0.23.jar
-
添加工具类(JDBCUtils最终版)
-
在src下添加工具类所需的
jdbc.properties
-
书写实体类
-
搭建DAO
- 必须测试
-
搭建Service
- 最好也进行测试
-
书写view(不需要过多关注,实际开发中该层对接的应该是浏览器页面)
项目结构图示:
高效掌握JDBC的分享到此结束,希望对大家有所帮助,如有疑问欢迎大家交流指正。
以上是关于高效掌握JDBC技术| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤的主要内容,如果未能解决你的问题,请参考以下文章
高效掌握JDBC技术| 掌握ORM思想 | 定义连接数据库的工具类