目录
一、JDBCUtil工具类
(1) 定义一个类名为 JDBCUtil类
(2) 类中提供两个静态方法:
a. public static Connection getConnection(){
// 1. 加载驱动类
// 2. 获取连接
}
b. public static void close(ResultSet rs,PreparedStatement pstm,Connection conn){
// 6. 释放资源
}
(3) 第一个版本解决了代码的冗余问题:将JDBC开发中六个步骤中重复的步骤进行提取
(4) 存在的问题:没有解决因数据库改变而造成代码的更改,将特定的数据库相关配置内容写死在了代 码,不灵活性
2. JDBCUtil的第二个版本:
(1) 解决:因数据库不同出现参数不同,提高灵活性、通用性
(2) 在当前的项目下创建一个包:
/com/baizhi/zmj/conf
在包中定义一个配置文件,以 .properties结尾,例如:db.properties
存储的内容为:4个部分
mydriver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db2202?characterEncoding=utf-8
username=root
password=root
注意:文件中不能随意出现空格和分号
(3) 利用 Map的实现类:Properties,默认泛型为String类型(key-value)
a. 提供 load(输入流):自动将输入指向的文件自动加载到Properties中,自动的以=做分割; =左边的作为键(key),=右边的作为值(value);每行内容对应一个键值对
注意:输入流:
InputStream in = 类名.class.getResourceAsStream("/文件的路径");
写路径时,必须 /开头,从当前的Module的src目录的下一级开始写,以 / 开头,
写到 配置文件名位置即可(com.baizhi.zmj.conf-->/com/baizhi/zmj/conf/文件名)
InputStream in = JDBCUtil.class.getResourceAsStream("/com/baizhi/zmj/conf/db.properties");
b. 提供 getProperty方法:可以根据键获取对应值
pro.getProperty(key);
注意:如果更换数据库时,改变的是 = 右边,不变为=左边内容,通过不变 的key获取变动 value
3. 第三版本:
(1) 在第二个版本基础上:将读取配置文件定义在 静态代码块中,静态代码块中的内容只有在类加载时 执行一次
(2) 好处:提高程序的效率,减少配置文件读取的次数
(3) static{}
二、Dao
1. Dao:Data Access Object,数据访问对象
2. dao中需要封装对一张表的增删改查等操作
3. Dao类设计的思想:通常利用一个类对应 数据库中一张表,对表中的不同sql操作,对应类中的每 一个方法
(1) 通常对表中 增删改查操作需求,对应类Dao类中方法个数
(2) 通常Dao类中每一个方法,对应一个 sql
(3) 每一个方法的开发步骤为 :6步骤
1~2:通过 JDBCUtil获取连接
3:准备sql,准备发送sql的工具
4. 绑定参数,同时发送sql
5. 处理结果集
6. 利用 JDBCUtil释放资源
4. Dao类命名:
(1) 表名+Dao
(2) 表 Dao类名
students StudentDao/StudentsDao
t_teacher TeacherDao
注意:每一个单词首字母大写,而且去除 数据库中 _内容
(3) Dao类存储的位置:com.baizhi.zmj.dao包中
(4) 注意:在dao中每个方法出现的 sql必须在 navicat测试
5. ORM:
(1) ORM:Object Relational Mapping,对象关系映射,Java中的一个类对应数据库中一张表
注意:Java中的一个对象对应表中的一行数据
(2) 和表映射对应的类称之为实体类,要求如下:
a. 类名 取决于 对应的表名,通常将对应的表名首字母大写作为类名
Java中类名 数据库中表名
Student/Students students
Teacher t_teacher
b. 实体类需要实现 java.io.Serializable接口
c. 实体类中的数据:个数、类型、名字同表的字段
表的字段类型 属性的类型
int int/Integer(建议)
double double/Double
varchar/char String
表的字段名 属性名
stuId stuId
stu_name stuName(去除_)
d. 属性要求私有化,提供公开的get/set方法
e. 提供构造方法:一个无参数的方法和有参数的构造方法(取决于自身类中属性)
f. 覆盖 toString
6. Dao 中常见的方法:
class 表名+Dao{ // 表名需要大写
// 删除
public void deleteById(int id){}
// 根据id查一个
public Account selectOneById(int id){}
// 查所有
public List selectAll(){}
// 插入
public void insert(Account acc){}
// 修改
public void update(Account acc){}
// 模糊查询
public List selectLike(String name){}
}
三、业务层
1. 业务:代表根据用户需求完成一个功能,通常由一次或者多次调用dao中的方法完成
2. 业务类:专注于对用户的业务功能进行处理,一个业务对应业务类中一个方法
(1) 业务类:望文生义,XxxService,AccountService/BankService
(2) 业务类中每一个方法代表一个业务功能,方法名望文生义即可,transMoney
(3) 完成业务功能的过程中需要控制事务:
a. 需要将业务中一次或是多次调用dao中的方法看做整体,都执行成功,事务提交;只要有一个失败, 回滚
b. 事务:回顾
I. 事务:由一条或是多条sql组成,全部执行成功,事务提交(commit);只要有一条sql执行失 败,事务回 滚(rollback,撤销已经执行的sql结果)
II. 一个业务功能对应一个事务,业务的大小决定了事务的sql的组成
III. 利用 JDBC中事务控制,保证事务的原子性
3. JDBC中事务控制相关API
(1) 目前事务控制失败的原因:JDBC中默认自动提交事务,只要一条sql执行完毕,则自动提交
(2) 控制的常见方法,位于Connection中:
Connection conn = JDBCUtil.getConnection();// 先获取连接
conn.setAutoCommit(false);// 将事务的提交方式设置为手动
conn.commit();// 提交事务
conn.rollback();
(3) 业务控制事务的模板:
public 返回值类型 业务的方法名(参数){
Connection conn = null;
try{
// 1. 通过 JDBCUtil获取连接
conn = JDBCUtil.getConnection();
// 2.设置提交方式为手动
conn.setAutoCommit(false);
// 3.调用dao的方法,完成业务功能(可能多次调用)
dao.
...
// 4. 事务提交 conn.commit();
}catch(Exception e){
// 4. 事务回滚
conn.rollback();
}finally{
// 5. 利用JDBCUtil释放资源
JDBCUtil.close(null,null,conn);
}
}
4. 事务控制失败的原因:
业务层service调用dao层的方法来实现对应的业务,业务层和dao层都是通过JDBCUtil获取的新的连 接(service和dao层使用为不同的连接),在service设置提交方式为手动,无法控制dao层提交方 式,dao层提交方式依然默认为自动提交方式(只要执行一条sql,自动的commit,一旦commit之后, rollback起不到回滚的作用)
5. 解决问题的思路:需要保证一个业务中的service和dao层获取同一个连接
6. ThreadLocal:利用ThreadLocal解决service和dao层连接不统一的问题
(1) ThreadLocal理解为存储连接一种容器
(2) ThreadLocal常见的操作:
ThreadLocal tl = new ThreadLocal<>();
tl.get(); // 获取连接
tl.set(conn); // 将获取的连接存入到ThreadLocal中
tl.remove();// 清除 tl中的连接
7. JDBCUtil的最终版本
8. 注意:在dao层连接不要关闭,service层关闭连接!!!!!!
四、JDBC的分包分层
1. JDBC中分层(三层)
(1) Dao层:数据访问层,专注于对数据库的CURD(增删改查),和数据库直接打交道
注意:此层开发分为6个步骤
(2) service层:业务层,专注实现用户业务需求的,控制事务
注意:此层开发分5个步骤
(3) view层:视图层,专注给用户做展示同时接受用户输入信息,利用 System.out.println()/Scanner
注意:利用普通代码完成,和JDBC开发代码无关,随着需求,此层被替换
注意:view调用--> service中的方法-->dao层中方法,逐层调用,不能跨越!!!
2.分层的好处
(1)各司其职,降低代码耦合度
(2)便于分工,利用协同开发
3. JDBC的分包
com.baizhi.zmj.conf:存储数据库相关配置文件
com.baizhi.zmj.util:存储工具类,例如:JDBCUtil,测试工具
com.baizhi.zmj.test:测试存储位置
com.baizhi.zmj.sql:存储sql
com.baizhi.zmj.entity:存储实体类
com.baizhi.zmj.dao:先接口(XxxDao),再实现类(XxxDaoImpl)
注意:dao中方法必须每一个测试!!!连接不要关闭!!
com.baizhi.zmj.service:先接口(XxxService),再实现(XxxServiceImpl)
注意:service中方法必须每一个测试!!!!!!
com.baizhi.zmj.view:界面 XxxView
五、JDBC项目开发的步骤:
创建新的项目 Project(已经存在,直接应用)
创建新的 在 Module的根上和src并列的位置,创建文件夹(目录):lib
1. 需要将Jar拷贝此文件夹
2. 右键 --》add Libaray as
注意:先利用 navicat创建项目需要的 table
在 src上,创建相关的package
1. com.baizhi.zmj.conf:存储 配置相关文件,例如 db.properties
注意:配置文件中数据库名字需要根据操作表所在库表位置发生改变
2. com.baizhi.zmj.util:存储工具类,例如:JDBCUtil.java
注意:需要测试连接是否获取!!!!!
不通过:查看读取配置文件的路径是否正确(路径的单词是否写错);
查看jar是否导入,是否有 右键 add Libaray as
3. com.baizhi.zmj.test:测试相关代码,例如:TestConnection
---------------完成以上的环境搭建,开始进入项目完成代码-------------
4. com.baizhi.zmj.sql:数据库表结构
5. com.baizhi.zmj.enyity:实体类,通常一个表对应一个类(取决表)
6. com.baizhi.zmj.dao:先接口再实现
注意:dao中每一个方法都必须测试!!!此层连接不能关闭!!!
7. com.baizhi.zmj.service:先接口再实现
注意:service中每一个方法必须测试!!!此层需要关闭连接!!!
8. com.baizhi.zmj.view:视图层