1.自定义 Mybatis 框架的分析
0.0软件开发的分层重要性
框架的重要性在于它实现了部分功能,并且能够很好的将低层应用平台和高层业务逻辑进行了缓和。为了实现软件工程中的“高内聚、低耦合”。把问题划分开来各个解决,易于控制,易于延展,易于分配资源。我们常见的 MVC 软件设计思想就是很好的分层思想。
三层架构: 通过分层更好的实现了各个部分的职责,在每一层将再细化出不同的框架,分别解决各层关注的问题
持久层总图:
Mybatis分析:
1.0 jdbc 程序的回顾
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//通过驱动管理类获取数据库链接
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8","ro ot", "root");
//定义 sql 语句 ?表示占位符
String sql = "select * from user where username = ?";
//获取预处理 statement
preparedStatement = connection.prepareStatement(sql);
//设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
preparedStatement.setString(1, "王五");
//向数据库发出 sql 执行查询,查询出结果集
resultSet = preparedStatement.executeQuery();
//遍历查询结果集
while(resultSet.next()){
System.out.println(resultSet.getString("id")+" "+resultSet.getString("username"));
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//释放资源
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(preparedStatement!=null){
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
上边使用 jdbc 的原始方法(未经封装)实现了查询数据库表记录的操作。
1.1知识点介绍
构建一个属于自己的持久层框架,将会涉及到的一些知识点:工厂模式 (Factory 工厂模式)、构造者模式(Builder 模式)、代理模式,反射,自定义注解,注解的反射,xml 解析, 数据库元数据,元数据的反射等。
1.2 分析流程
入门案例分析:
mybatis在使用代理dao的方式实现增删改查时做了什么事?
两件事:
1.创建代理对象
2.在代理对象中调用selectList
自定义mybatis分析:
1.2.1自定义mybatis
用到的类:
- class Resources
- class SqlSessionFactoryBuilder
- interface SqlSessionFactory
- interface SqlSession
1.3 自定义 Mybatis 的设计模式说明
工厂模式
代理模式
构建者模式
1.4 自定义流程再分析
2. Mybatis 的参数深入
2.1 parameterType 配置参数
- parameterType属性的取值可以是基本类型,引用类型(例如:String 类型),还可以是实体类类型(POJO 类)。同时也可以使用实体类的包装类,此处将介绍如何使用实体类的包装类作为参数传递。
- (1)基本类型和 String 我们可以直接写类型名称 ,也可以使用包名 . 类名的方式 ,例如 java.lang.String。
(2)实体类类型,目前我们只能使用全限定类名。
究其原因,是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名, 而我们的是实体类并没有注册别名,所以必须写全限定类名。
2.2 Mybatis的输出结果封装
2.2.1 resultType 配置结果类型
1.resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。
2.我们在前面的 CRUD 案例中已经对此属性进行过应用了。
需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须 使用全限定类名。例如:我们的实体类此时必须是全限定类名。
同时,当是实体类名称是,还有一个要求,实体类中的属性名称必须和查询语句中的列名保持一致,否则无法 实现封装。
2.2.2.可以使用别名查询
使用别名查询
select id as userId,username as userName,birthday as userBirthday, sex as userSex,address as userAddress from user
`注:mysql 在 windows 系统中不区分大小写!
2.2.3resultMap 结果类型
resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。 在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
定义 resultMap
<!-- 建立 User 实体和数据库表的对应关系
type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的。 -->
<resultMap type="com.itheima.domain.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
</resultMap>
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>
3.Mybatis 传统 DAO 层开发[了解]
使用 Mybatis 开发Dao,通常有两个方法,即原始 Dao开发方式和 Mapper 接口代理开发方式。而现在主流 的开发方式是接口代理开发方式,这种方式总体上更加简便
3.1 持久层 Dao 接口
public interface IUserDao {
/**
* 查询所有用户
* * @return
*/
List<User> findAll();
/**
* 根据 id 查询
* * @param userId
* @return
*/
*User findById(Integer userId);
/**
* 保存用户
* * @param user
* * @return 影响数据库记录的行数
*/
int saveUser(User user);
/**
* 更新用户
* * @param user
* * @return 影响数据库记录的行数
*/
int updateUser(User user);
/**
* 根据 id 删除用户
* * @param userId *
* @return
*/
int deleteUser(Integer userId);
/**
* 查询总记录条数
* * @return
*/
* int findTotal();
}
3.2 持久层 Dao 实现类
public class UserDaoImpl implements IUserDao {
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
@Override
public List<User> findAll() {
SqlSession session = factory.openSession();
List<User> users = session.selectList("com.itheima.dao.IUserDao.findAll");
session.close();
return users;
}
public User findById(Integer userId) {
SqlSession session = factory.openSession();
User user = session.selectOne("com.itheima.dao.IUserDao.findById",userId);
session.close();
return user;
}
@Override
public int saveUser(User user) {
SqlSession session = factory.openSession();
int res = session.insert("com.itheima.dao.IUserDao.saveUser",user);
session.commit();
session.close();
return res;
}
@Override
public int updateUser(User user) {
SqlSession session = factory.openSession();
int res = session.update("com.itheima.dao.IUserDao.updateUser",user);
session.commit();
session.close();
return res;
}
@Override
public int deleteUser(Integer userId) {
SqlSession session = factory.openSession();
int res = session.delete("com.itheima.dao.IUserDao.deleteUser",userId);
session.commit();
session.close();
return res;
}
@Override
public int findTotal() {
SqlSession session = factory.openSession();
int res = session.selectOne("com.itheima.dao.IUserDao.findTotal");
session.close();
return res;
}
}
3.3 持久层映射配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.dao.IUserDao">
<!-- 配置查询所有操作 -->
<select id="findAll" resultType="com.itheima.domain.User">
select * from user
</select>
<!-- 根据 id 查询 -->
<select id="findById" resultType="com.itheima.domain.User" parameterType="int">
select * from user where id = #{
uid}
</select>
<!-- 保存用户
ognl 表达式:它是 apache 提供的一种表达式语言,在 struts2 中也有应用。
Object Graphic Navigation Language 对象图导航语言
它是按照一定的语法格式来获取数据的。
语法格式就是使用 #{
对象.对象}的方式
#{
user.username}它会先去找user 对象,然后在user对象中找到username属性,并把值取出来 -->
<insert id="saveUser" parameterType="com.itheima.domain.User">
<!-- 配置保存时获取插入的 id -->
<selectKey keyColumn="id" keyProperty="id" resultType="int">
select last_insert_id();
</selectKey>
insert into user(username,birthday,sex,address) values(#{
username},#{
birthday},#{
sex},#{
address})
</insert>
<!-- 更新用户 -->
<update id="updateUser" parameterType="com.itheima.domain.User">
update user set username=#{
username},birthday=#{
birthday},sex=#{
sex},address=#{
address} where id=#{
id}
</update>
<!-- 删除用户 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{
uid}
</delete>
<!-- 查询总记录条数 -->
<select id="findTotal" resultType="int">
select count(*) from user;
</select>
</mapper>
3.4 编写Dao实现mybatis的执行过程
3.5 代理Dao实现mybatis的执行过程
4.SqlMapConfig.xml配置文件
4.1 配置内容
4.1.1 SqlMapConfig.xml 中配置的内容和顺序
-properties(属性)
--property
-settings(全局配置参数)
--setting
-typeAliases(类型别名)
--typeAliase
--package -typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
--environment(环境子属性对象)
---transactionManager(事务管理)
---dataSource(数据源)
-mappers(映射器)
--mapper
--package
4.2 properties(属性)
在使用 properties 标签配置时,我们可以采用两种方式指定属性配置。
第一种:
<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="1234"/>
</properties>
第二种:
在 classpath 下定义 db.properties 文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy
jdbc.username=root
jdbc.password=1234
4.3 typeAliases(类型别名)
Mybatis 支持默认别名,我们可以采用自定义别名方式来开发。
自定义别名:
在 SqlMapConfig.xml 中配置:
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.itheima.domain.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以)用于指定实体类的包. -->
<package name="com.itheima.domain"/>
<package name=" 其它包 "/>
</typeAliases>
4.4 mappers(映射器)
4.4.1 mapper resource
使用相对于类路径的资源
如:<mapper resource="com/itheima/dao/IUserDao.xml" />
4.4.2 mapper class
使用 mapper 接口类路径
如:<mapper class="com.itheima.dao.UserDao"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
4.4.3 package name
注册指定包下的所有 mapper 接口
如:<package name="cn.itcast.mybatis.mapper"/>
package标签是用于指定dao接口所在的包,当指定了之后就不需要在写resource和class了.
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。