[1]上一篇博客的开发过程如下
-
创建table
-
封装实体类
-
写DAO
-
写测试
[2]本文添加业务层 – Service
主要的操作:
-
验证数据
-
调用dao
-
控制事务
-
业务层就是封装了业务功能的操作,通过调用DAO来完成.
-
业务功能根据业务的复杂程度不同,会一次或多次的调用 dao
-
编程思路
[3]JDBC中的事务
-
JDBC中的事务默认是自动提交,一条sql自成一个事务,执行成功就提交。
-
对于一条sql语句自成一个事务, 不好,我们需要设置手动提交事务
-
设置JDBC的手动控制事务(由Connection对象来控制): conn.setAutoCommit(false);
-
手动提交事务: conn.commit();
-
事务回滚: conn.rollback();
[4]对工具类的最终版本分析
-
由于service和dao使用的不是同一个conn对象,导致了事务没有控制住。
-
解决办法: 让service 和dao使用同一个连接
-
第一种方案: 可以 将service创建好的Connection传给dao, 在dao的每一个方法上加一个参数 // 这种方式不用 存在api的入侵污染
-
第二种方案:引入
ThreadLocal
对象到工具类中-
ThreadLocal
的作用: 可以将一个对象绑定到当前线程。- 存值: tol.set(value);
- 取值: tol.get();
- 移除: tol.remove();
-
package cn.net.trimmer.jdbc.util; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Properties; /** * jdbc 工具类简单抽取 * * @author wl * */ public class JdbcUtils { private static final Properties prop = new Properties(); private static final ThreadLocal<Connection> tol = new ThreadLocal<>(); // 类加载时读取配置文件 static { InputStream in = null; try { // 1. 从类路径加载配置文件 in = JdbcUtils.class.getResourceAsStream("/cn/net/trimmer/jdbc/conf/db.properties"); // 2. 解析配置文件 prop.load(in); System.out.println("数据库配置文件加载完成..."); } catch (IOException e) { e.printStackTrace(); if (in != null) { try { in.close(); } catch (IOException e1) { e1.printStackTrace(); } } } } /** * 获取数据库连接对象 * * @return conn 数据库连接对象 */ public static Connection getConn() { // 从线程局部变量中取连接对象 Connection conn = tol.get(); try { // 连接对象不存在则创建 if (conn == null) { String driver = prop.getProperty("jdbc.driver"); String url = prop.getProperty("jdbc.url"); String username = prop.getProperty("jdbc.username"); String password = prop.getProperty("jdbc.password"); Class.forName(driver); conn = DriverManager.getConnection(url, username, password); // 存入连接对象到线程局部变量中 tol.set(conn); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } return conn; } /** * 释放资源 * * @param rs 执行结果集 * @param stm sql操作对象 * @param conn 数据库连接 */ public static void release(ResultSet rs, Statement stm, Connection conn) { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } if (stm != null) { try { stm.close(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } if (conn != null) { try { // 关闭连接 conn.close(); // 清除线程局部变量 tol.remove(); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException(e); } } } }
-
-
注意: 当service与dao使用同一个连接后,关闭连接的操作必须有 service完成,在dao中不能关闭连接。
-
[5]三层架构设计(编程思想)
-
图例:
-
三层架构的好处
解耦和 , 利于系统的扩展 ,便于后续的维护升级。
-
service和dao开发中引入接口 – 引入接口后的核心编程思路
#1.创建表 表名叫啥,这个表是存储什么类型数据的,表中有哪些字段,每个字段的约束 #2.封装实体类 一个实体类对应一个table, 属性私有,属性名一般对应表的字段名,提供get/set方法 (高配 加 有参 和无参构造方法 提供toString方法) 实现序列化接口 -- Serializable #3.定义DAO接口 一个dao对应一张表的操作 命名: AccountDao #4.写DAO接口的实现 命名:AccountDaoImpl #5.定义service接口 要完成哪些业务操作 命名:AccountService #6.写service的实现 命名:AccountServiceImpl
-
项目环境搭建
i.导入需要的jar包
ii. 引入配置文件
iii. 创建包结构
iii.导入工具类
[6]关于日期类型
-
java.util.Date()
创建:
java.util.Date utilDate = new java.util.Date();
– 拿到的是一个当前系统时间//Fri May 19 11:27:32 CST 2017注意: 不能将util类型的日期直接插入表中Date类型的字段
-
java.sql.Date()
创建:
java.sql.Date sqlDate = new java.sql.Date(long类型的日期表现形式 -- utilDate.getTime());
注意:当向数据库表中字段类型为Date的列 插入的日期 , 在JDBC中必须是java.sq.Date()l类型的Date
-
字符串与日期类型的转换 – SimpleDateFotmat
i . 创建:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
ii. 使用sdf将字符串 转成 日期:
java.util.Date utilDate = sdf.parse(str);
iii. 将一个java.util.Date() – 字符串:
String str = sdf.format(utilDate );
iv. 通过java.util.Date() – 获取一个
java.sql.Date(): java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());