全部章节 >>>>
本章目录
1.4.2 mapUnderscoreToCamelCase属性
1.1 初识MyBatis
1.1.1 持久化技术介绍
数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。
狭义的讲就是将内存中的数据存储到数据库或其他介质的过程。
Dao层将数据存储到数据库中
Java如何实现数据持久化?
JDBC编程操作:
- 代码重复繁琐、开发效率低
Mybatis、Hibernate等框架技术
- 企业级应用开发
- 支持多种数据库切换
- 封装了传统JDBC提高开发效率
- 插件丰富、安全性高、支持缓存等
1.1.2 MyBatis简介
MyBatis的前身是iBatis,是在2001年发起的一个开源项目,2010年更名为MyBatis,是目前企业级数据库操作使用最多的框架之一。
MyBatis是一款优秀的支持自定义SQL查询、存储过程和高级映射的持久层框架,几乎封装所有的JDBC代码和参数的手动设置以及结果集的检索,通过XML或注解的方式进行配置映射实现数据库操作,大大提高了开发效率。
1.1.2 Mybatis优点
MyBatis优势:
- 易于学习,易于使用,丰富的文档和源代码
- 提供了数据映射功能(ORM),消除了繁琐的JDBC代码
- 降低了程序和SQL语句的耦合
- 提供了连接管理,缓存支持,线程支持,(分布式)事务管理等
1.1.3 利用Maven添加MyBatis依赖包
在Eclipse中创建一个基本的Maven项目,操作步骤如下:
- 新建Maven项目,点击Next
- 选择 Create a simple project
- 输入项目包名、工程名、版本信息
- 点击Finish完成构建Maven项目
- 修改项目下maven配置文件pom.xml
- 在pom.xml中添加mybatis依赖支持
- 继续在pom.xml中添加JUnit、log4j、slf4j和MySQL驱动的依赖
- 右键项目在【Maven】中选择【Update Project...】来更新外部依赖的jar包(此时会先从本地maven配置的仓库去寻找jar,如果没有则会上网下载)
查找地址:https://mvnrepository.com/
1.1.4 实践练习
1.2 开发一个简单的MyBatis应用
1.2.1 mybatis核心配置文件
要使用Mybatis实现数据库操作,首先需要在 src/main/resources 目录下创建mybatis核心配置文件mybatis-config.xml。
别名配置:
<typeAliases>
<package name="jack.mybatis.simple.model" />
</typeAliases>
项目中实体类包名,配置后mybatis才识别实体类名称
操作具体表的SQL语句映射文件:
<mappers>
<mapper resource="jack/mybatis/mapper/CountryMapper.xml"/>
</mappers>
映射文件完整路径
具体数据源配置(可以配置多个,选择其中一个使用):
<environments default=“development”> <!-定义数据源,默认使用第一个-->
<environment id="development"> <!-- 每个environment元素定义的环境id-->
<dataSource type="UNPOOLED"> <!-- 数据源配置 -->
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/db_mybatis" />
<property name="username" value="root" />
<property name="password" value="abc123" />
</dataSource>
</environment>
</environments>
1.2.2 定义实体类
MyBatis是一个结果映射框架,创建一个和数据库表对应的实体类。
在实体类包(jack.mybatis.simple.model)下新建实体类 Country
public class Country {
private String countrycode;
private String countryname;
private Long id;
// 属性getter()方法和setter()方法
}
1.2.2 定义接口映射
在src/main/resources下面创建 jack/mybatis/simple/mapper 目录,该目录下面创建与实体类Country对应的映射文件CountryMapper.xml文件
<!-- 映射器名字空间,即CountryMapper类的全限定名称 -->
<mapper namespace="jack.mybatis.simple.mapper.CountryMapper">
<select id="selectAll" resultType="Country">
select id,countryname,countrycode from country
</select>
</mapper>
id="selectAll" id和接口方法名对应
resultType="Country" resultType代表返回的结果类型,和实体类对应
namespace="jack.mybatis.simple.mapper.CountryMapper" mybatis会自动产生该接口
CountryMapper名称必须是实体类+Mapper组合 <select>标签对应查询语句,还有insert、update、delete标签对应
1.2.3 配置Log4j日志
Log4j用于将MyBatis执行过程中的SQL和其他信息输出到控制台:
在src/main/resources中添加log4j.properties配置文件,代码如下:
#全局配置
log4j.rootLogger=ERROR, stdout
#MyBatis日志配直
log4j.logger.jack.mybatis.simple.mapper=TRACE
#控制台输出配置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
1.2.4 测试MyBatis
在src/test/java中创建jack.mybatis.simple.mapper包,然后创建CountryMapperTest测试类,以下为测试类初始化方法:
1、完成mybatis配置的加载,创建得到SqlSessionFactory
@BeforeClass
public static void init () {
try {
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); 加载配置文件,创建SqlSessionFactory
2、从SqlSessionFactory对象中获取SqlSession对象,用于调用方法得到数据:
@Test
public void testSelectAll() {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
List<Country> countryList = sqlSession.selectList("selectAll");
//调用打印数据方法,也可以这里输出
printCountryList(countryList);
} finally {
// 不要忘记关闭sqlSession
sqlSession.close();
}
}
SqlSession sqlSession = sqlSessionFactory.openSession(); 得到SqlSession对象
List<Country> countryList = sqlSession.selectList("selectAll"); 调用方法查询数据 selectAll为xml映射文件中定义的查询id
1.2.5 实践练习
1.3 MyBatis单表查询
1.3.1 分析权限控制需求
权限控制系统中,一个用户拥有若干角色,一个角色拥有若干权限。权限就是对某个资源(模块)的某种操作(增、删、改、查),这样就构成了“用户—角色—权限”的授权模型。
- 用户表 sys_user
- 角色表 sys_role
- 用户角色关联表 sys_user_role
- 权限表 sys_privilege
- 角色权限关联表 sys_role_privilege
1.3.2 MyBatis单表查询实现方法
使用MyBatis实现根据用户id获取用户信息的步骤如下:
创建maven项目,添加mybatis依赖支持
创建实体类包和用户实体类SysUser.java
package entity;
public class SysRole {
private long id;
private String roleName;
private int enabled;
private String createBy;
private String createTime;
public SysRole() {
super();
}
public SysRole(long id, String roleName, int enabled, String createBy, String createTime) {
super();
this.id = id;
this.roleName = roleName;
this.enabled = enabled;
this.createBy = createBy;
this.createTime = createTime;
}
@Override
public String toString() {
return "SysRole [id=" + id + ", roleName=" + roleName + ", enabled=" + enabled + ", createBy=" + createBy
+ ", createTime=" + createTime + "]";
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public int getEnabled() {
return enabled;
}
public void setEnabled(int enabled) {
this.enabled = enabled;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
}
一般表中int在实际中会使用Integer和Long
byte[]一般对应blob等二进制流类型
创建对实体进行DAO操作的映射器接口
public interface UserMapper {
// 根据用户id查询一个用户实体
public SysUser selectById(Long id);
}
id是查询的参数条件值
这里自己定义了操作的接口,接口中方法无需实现,由mybatis运行时进行实现
在resources对应目录下定义接口的映射配置文件:UserMapper.xml
<mapper namespace="jack.mybatis.authority.mapper.UserMapper">
<resultMap type="SysUser" id="userMap">
详细映射说明
</resultMap>
<select id="selectById" resultMap="userMap">
select * from sys_user where id = #{id}
</select>
</mapper>
如果实体类中属性名和表列名一致,resultMap="userMap">可以直接写resultType
id为接口定义传入的参数名
<resultMap type="SysUser" id="userMap">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<result property="userEmail" column="user_email"/>
<result property="userInfo" column="user_info"/>
<result property="headImg" column="head_img" jdbcType="blob"/>
<result property="createTime" column="create_time" jdbcType="timestamp"/>
</resultMap>
实体类中的属性名和数据表的列名不对应,运行会直接报错,需要添加映射说明
配置mybatis-config.xml核心配置文件
<environment id="development"> <!-- 每个environment元素定义的环境id-->
<dataSource type="UNPOOLED"> <!-- 数据源配置 -->
<property name=“driver” value=“com.mysql.jdbc.Driver” />
<property name=“url” value=“jdbc:mysql://localhost:3306/数据库名" />
<property name="username" value="root" />
<property name="password" value="abc123" />
</dataSource>
</environment>
<!--加入对接口映射文件的注册识别,否则mybatis无法正常运行-->
<mappers>
<mapper resource="jack/mybatis/authority/mapper/UserMapper.xml" />
</mappers>
一定要将接口映射xml文件注册到mybatis核心配置中
测试实现,关键代码如下:
//加载mybatis配置文件代码略
//获取SqlSessionFactory对象
//获取接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 调用selectByid方法,查询id=1的用户
SysUser user = userMapper.selectById(1L);
printUser(user);
自己定义接口的方式需要获取接口代理对象
1.3.3 实践练习
1.4 无嵌套的MyBatis多表查询
1.4.1 resultMap和resultType
resultType用于定义返回或者参数的类型,如果返回的是集合则只需要定义集合中的实体类型即可,如果未在核心配置中指明typeAliases,则需要写全路径名。
public List<SysUser> selectUsers();
resultMap用于定义当查询的结果字段和接收的实体类字段不一致时,进行映射说明,如下:
<resultMap type="SysUser" id="userMap">
<id property="id" column="id"/>
<result property="userName" column="user_name"/>
<result property="userPassword" column="user_password"/>
<result property="userEmail" column="user_email"/>
</resultMap>
property="userName" 对应实体中属性名
column="user_name" 对应表中的列名
1.4.2 mapUnderscoreToCamelCase属性
数据库中下划线方式的命名很常见,但是Java中而是使用驼峰式命名,如userName、userEmail等,这样mybatis在结果返回和实体类对应时无法直接关联,需要定义resultMap增加了复杂度。
MyBatis提供了一个全局属性mapUnderscoreToCamelCase,通过配置该属性为true可以自动将以下划线方式命名的数据库列映射到Java对象的驼峰式命名属性中。
<settings>
<!—其他配置-->
<!--将以下划线方式命名的数据库列映射到Java对象的驼峰式命名属性中-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
1.4.3 MyBatis多表查询实现方法
实际业务中还需要多表关联查询。关联查询结果的类型也会有多种情况:
情况1:多表查询结果只包含一个表的信息 根据用户id获取用户拥有的所有角色,虽然查询时关联三个表,但是返回的结果为角色集合,查询结果只有角色的信息。
// 根据用户id获取角色信息
List<SysRole> selectRolesByUserid(Long id);
<!—对应映射xml中的sql和配置-->
<select id="selectRolesByUserid" resultType="SysRole">
select r.id,r.role_name roleName,r.enabled,r.create_by createBy,r.create_time createTime
from sys_role r join sys_user_role ur on r.id=ur.role_id join sys_user u on u.id=ur.user_id
where u.id=#{userId}
</select>
情况2:多表查询结果包含多个表的信息
根据用户id获取用户拥有的所有角色,假设查询的结果不仅要包含角色信息,还要包含当前用户的部分信息(不考虑嵌套的情况)
解决1:在SysRole对象中直接添加userName属性,这样仍然使用SysRole作为返回值
解决2:创建一个新类SysRoleExtend继承SysRole,如下:
public class SysRoleExtend extends SysRole{
private String userName; //添加SysRole中没有的属性,而查询结果中需要包含的
…. 其他需要包含的
//产生get和set方法
}
将resultType设置为扩展属性后的SysRoleExtend对象,通过这种方式来接收多余的值,如果需要其他表中大量列的值时,这种方式就不适用了,因为我们不能将一个类的属性都照搬到另一个类中。
情况3: 使用对象作为成员属性的方式接收多表数据,需要角色SysRole的数据,还需要SysUser的数据,而SysRole中无法存储SysUser的数据,所以直接将一个SysUser对象放入SysRole中作为成员属性。
public class SysRole {
// 其他原有属性
private SysUser user; // 用户信息
...
}
该属性是一个用户对象, 可以将查询的用户信息封装进去
修改UserMapper.xml中selectRolesByUserid的SQL,达到能够将用户的数据放入SysUser成员属性对象中,代码如下:
<select id="selectRolesByUserid" resultType="SysRole">
select r.id,r.role_name,r.enabled,r.create_by,r.create_time,u.user_name as "user.userName" from sys_role r join sys_user_role ur on r.id=ur.role_id join sys_user u on u.id=ur.user_id where u.id=#{userId}
</select>
红色的为列的别名,user则对应SysRole实体中的user实体对象名
1.4.4 实践练习
总结
- MyBatis是一款优秀的支持自定义SQL查询、存储过程和高级映射的持久层框架技术,能够根据配置自动产生操作数据库的JDBC代码,从而大大提高了Java数据库操作的开发效率。
- 使用Mybatis需要添加相关依赖,创建mybatis-config.xml核心配置文件,配置全局属性、数据源和实体包的别名,并导入定义SQL语句的Mapper.xml。
- 具体操作时需要加载MyBatis相关配置文件,创建SqlSessionFactory,然后获取SqlSession对象,拿到相关Mapper接口,从而实现调用。