MyBatis学习笔记
MyBatis学习笔记
MyBatis简介
mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,
而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
mybatis 通过 xml 或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中
sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并
返回。
采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我
们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。
MyBatis的使用
单表的crud操作(使用配置文件的方式实现)
环境搭建
1.创建mybatisdb数据库,创建user四张表并插入数据
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` char(1) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user`(`id`,`username`,`birthday`,`sex`,`address`) values (41,'老王','2018-02-27 17:47:08','男','北京'),(42,'小二王','2018-03-02 15:09:37','女','北京金燕龙'),(43,'小二王','2018-03-04 11:34:34','女','北京金燕龙'),(45,'传智播客','2018-03-04 12:04:06','男','北京金燕龙'),(46,'老王','2018-03-07 17:37:26','男','北京'),(48,'小马宝莉','2018-03-08 11:44:00','女','北京修正');
2.新建maven工程
2.1 在pom.xml中导入相应的坐标
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
</dependencies>
2.2 编写user的实体类
public class User {
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
......
}
2.3 创建user的持久层接口
public interface UserDao {
//要实现的持久化操作
......
}
2.4 编写持久层接口的映射文件 UserDao.xml
<?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">
<!-- namespace:命名空间,写实体类持久化接口的全限定类名 -->
<mapper namespace="com.itheima.dao.UserDao">
<!-- 要配置的持久化操作 -->
......
</mapper>
2.5 引入相关配置文件
2.5.1 引入log4j.properties
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
2.5.2 引入 jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatisdb
jdbc.username=root
jdbc.password=123456
2.6 编写 SqlMapConfig.xml 配置文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--配置properties文件的位置-->
<properties resource="jdbcConfig.properties"></properties>
<typeAliases>
<!--批量别名定义,扫描整个包下的类,别名为类名-->
<package name="com.itheima.domain"></package>
</typeAliases>
<!-- 配置mybatis的环境 -->
<environments default="mysql">
<!--配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型 -->
<transactionManager type="jdbc"></transactionManager>
<!--配置数据源-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
</environment>
</environments>
<!--告知所有mybatis映射配置的位置-->
<mappers>
<package name="com.itheima.dao"></package>
</mappers>
</configuration>
2.7编写测试类
public class MybatisTest {
private InputStream in;
private SqlSession sqlSession;
private UserDao userDao;
@Before//测试方法执行前执行
public void init() throws IOException {
//读取配置文件生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取SqlSessionFactory构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//使用SqlSessionFactory构建者对象,用SqlMapConfig.xml的字节输入流生成SqlSessionFactory
SqlSessionFactory sqlSessionFactory = builder.build(in);
//用SqlSessionFactory生产一个sqlSession
sqlSession = sqlSessionFactory.openSession();
//用sqlSession获取代理对象
userDao = sqlSession.getMapper(UserDao.class);
}
@After//测试方法执行之后执行
public void destroy() throws IOException {
//提交事务
sqlSession.commit();
//关闭资源
sqlSession.close();
in.close();
}
}
查询user表的所有数据(findAll)
1.在UserDao中添加如下代码
/**
* 查找所有user
* @return
*/
List<User> findAll();
2.在UserDao.xml中添加如下配置
<!-- 配置查询所有的操作 -->
<!--
id:方法名 resultType:结果集的类型(由于在sqlMapConfig.xml配置了别名,这里写类名即可,否则要写全 限定类名,如:com.itheima.domain.User)
-->
<!-- 标签体内容为要执行的SQL语句 -->
<select id="findAll" resultType="User">
select * from user
</select>
3.在测试类添加测试代码
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
根据id查询user(findById)
1.在UserDao中添加如下代码
/**
* 根据id查找用户
* @param id
* @return
*/
User findById(Integer id);
2.在UserDao.xml中添加如下配置
<!--根据id查找用户-->
<!-- parameterType:传入的参数类型 -->
<!--
sql 语句中使用#{}字符:
它代表占位符, 相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
具体的数据是由#{}里面的内容决定的。
#{}中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。
-->
<select id="findById" parameterType="int" resultType="User">
select * from user where id = #{id}
</select>
3.在测试类添加测试代码
/**
* 测试根据id查找用户
*/
@Test
public void testFindById() {
User user = userDao.findById(48);
System.out.println(user);
}
根据姓名模糊查询(findByUsername)
1.在UserDao中添加如下代码
/**
* 根据姓名模糊查询
* @param username
* @return
*/
List<User> findByUsername(String username);
2.在UserDao.xml中添加如下配置
<!--根据姓名模糊查询-->
<!--
这里SQl语句有两种写法,这里采用第二种,如采用第一种写法,传入参数时要加入%。
第二种写法${}内固定写value
-->
<select id="findByUsername" parameterType="String" resultType="User">
<!-- select * from user where username like #{username} -->
select * from user where username like '%${value}%'
</select>
3.在测试类添加测试代码
/**
* 测试根据姓名模糊查询
*/
@Test
public void testFindByUsername() {
//List<User> users = userDao.findByUsername("%王%");//第一种写法
List<User> users = userDao.findByUsername("王");
for (User user : users) {
System.out.println(user);
}
}
user作为对象的属性时的查询(findByVo)
1.新建QueryVo类,添加属性user
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
2.在UserDao中添加如下代码
/**
* 根据vo查询
* @param vo
* @return
*/
List<User> findByVo(QueryVo vo);
3.在UserDao.xml中添加如下配置
<!--根据vo查询-->
<!-- user作为属性存在于QueryVo,先user在.username即可获取user的username -->
<select id="findByVo" parameterType="QueryVo" resultType="User">
select * from user where username like #{user.username}
</select>
4.在测试类添加测试代码
/**
* 测试根据vo查询
*/
@Test
public void testFindByVo() {
User user = new User();
user.setUsername("%王%");
QueryVo vo = new QueryVo();
vo.setUser(user);
List<User> users = userDao.findByVo(vo);
for (User u : users) {
System.out.println(u);
}
}
使用聚合函数查询总记录数(findTotal)
1.在UserDao中添加如下代码
/**
* 查询总记录数
* @return
*/
Integer findTotal();
2.在UserDao.xml中添加如下配置
<!--查询总记录数-->
<select id="findTotal" resultType="int">
select count(id) from user
</select>
3.在测试类添加测试代码
/**
* 测试查询总记录数
*/
@Test
public void testFindTotal() {
Integer total = userDao.findTotal();
System.out.println(total);
}
增加一个user(saveUser)
1.在UserDao中添加如下代码
/**
* 保存一个user
* @param user
*/
void saveUser(User user);
2.在UserDao.xml中添加如下配置
<!--配置保存一个user的操作-->
<!--
#{}中内容的写法:
由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。
它用的是 ognl 表达式。
ognl 表达式:
它是 apache 提供的一种表达式语言,全称是:
Object Graphic Navigation Language 对象图导航语言
它是按照一定的语法格式来获取数据的。
语法格式就是使用 #{对象.对象}的方式
#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用
getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user.而直接写 username。
-->
<insert id="saveUser" parameterType="User">
<!-- 配置保存时获取插入的 id -->
<selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
select last_insert_id()
</selectKey>
insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})
</insert>
3.在测试类添加测试代码
/**
* 测试保存用户
*/
@Test
public void testSaveUser() {
User user = new User();
user.setUsername("六花");
user.setBirthday(new Date());
user.setSex("女");
user.setAddress("日本");
System.out.println("保存前:" + user);
userDao.saveUser(user);
System.out.println("保存后:" + user);
}
修改user(updateUser)
1.在UserDao中添加如下代码
/**
* 更新用户
* @param user
*/
void updateUser(User user);
2.在UserDao.xml中添加如下配置
<!--更新用户-->
<update id="updateUser" parameterType="com.itheima.domain.User">
update user set username=#{username}, birthday=#{birthday}, sex=#{sex}, address=#{address} where id=#{id}
</update>
3.在测试类添加测试代码
/**
* 测试更新用户
*/
@Test
public void testUpdateUser() {
User user = userDao.findById(51);
user.setAddress("地球");
userDao.updateUser(user);
}
删除一个user(deleteUser)
1.在UserDao中添加如下代码
/**
* 删除用户
* @param id
*/
void deleteUser(Integer id);
2.在UserDao.xml中添加如下配置
<!--删除用户-->
<delete id="deleteUser" parameterType="Integer">
delete from user where id=#{id}
</delete>
3.在测试类添加测试代码
/**
* 测试删除用户
*/
@Test
public void testDeleteUser() {
userDao.deleteUser(49);
}
动态SQL:<if>和<where>
1.在UserDao中添加如下代码
/**
* 根据动态的条件查询
* @param user
* @return
*/
List<User> findByCondition(User user);
2.在UserDao.xml中添加如下配置
<!--根据动态的条件查询-->
<!-- 拼接SQL的原理 -->
<select id="findByCondition" resultType="User" parameterType="User">
<!--
select * from user where 1 = 1
<if test="username != null and username != ''">
and username = #{username}
</if>
-->
select * from user
<where><!-- where 1=1 的作用-->
<!--<if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。-->
<if test="username != null and username != ''">
and username = #{username}
</if>
<if test="sex != null">
and sex = #{sex}
</if>
</where>
</select>
3.在测试类添加测试代码
/**
* 测试根据传入的条件查询
*/
@Test
public void testFindByCondition() {
User user = new User();
user.setUsername("老王");
user.setSex("男");
List<User> users = userDao.findByCondition(user);
for (User u : users) {
System.out.println(u);
}
}
动态SQL:<foreach>
1.在QueryVo新增id的集合
private List<Integer> ids;
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
2.在UserDao中添加如下代码
/**
* 根据vo的id集合查询
* @return
*/
List<User> findByIds(QueryVo vo);
3.在UserDao.xml中添加如下配置
<!--根据vo的id集合查询-->
<select id="findByIds" parameterType="QueryVo" resultType="User">
select * from user
<where>
<if test="ids != null and ids.size() > 0">
<!--!
<foreach>标签用于遍历集合,它的属性:
collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符
-->
<foreach collection="ids" open="id in (" close=")" item="uid" separator=",">
#{uid}<!-- 作为id填充进括号内 -->
</foreach>
</if>
</where>
</select>
4.在测试类添加测试代码
/**
* 根据vo的id集合查询
*/
@Test
public void testFindByIds() {
ArrayList<Integer> ids = new ArrayList<Integer>();
ids.add(48);
ids.add(51);
ids.add(52);
QueryVo vo = new QueryVo();
vo.setIds(ids);
List<User> users = userDao.findByIds(vo);
for (User u : users) {
System.out.println(u);
}
}
多表查询之一对多
前期准备
具体参考单表的环境搭建,这里只演示新增和修改的部分
1.在数据库中新建用户的账户表account并插入数据
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
`ID` int(11) NOT NULL COMMENT '编号',
`UID` int(11) default NULL COMMENT '用户编号',
`MONEY` double default NULL COMMENT '金额',
PRIMARY KEY (`ID`),
KEY `FK_Reference_8` (`UID`),
CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `account`(`ID`,`UID`,`MONEY`) values (1,46,1000),(2,45,1000),(3,46,2000);
2.新建account实体类
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
//从表实体应该包含主表实体的对象引用,一个账户对应一个用户
private User user;
......
}
3.新建account的持久化操作接口AccountDao
public interface AccountDao {
......
}
4.编写持久层接口的映射文件 AccountDao.xml
<?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.AccountDao">
<!--定义封装Account和User的resultMap-->
<!--
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称
-->
<resultMap id="AccountUserMap" type="Account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--配置一对一关系映射:封装user-->
<association property="user" column="uid" javaType="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</association>
</resultMap>
<!--
抽取重复的语句代码片段,这里因为user的id和account的id重名了, 所以给account的id起了别名
-->
<!-- id 属性:给定一个唯一标识,是给<include/>标签引用用的。-->
<sql id="defaultSql">
select u.*, a.id as aid, a.uid, a.money from account a, user u where u.id = a.uid
</sql>
</mapper>
5.User类新增账户属性
//主表实体类要包含从表实体类的集合
private List<Account> as;
public List<Account> getAs() {
return as;
}
public void setAs(List<Account> as) {
this.as = as;
}
6.新建UserDao和UserDao.xml,编写UserDao.xml,增加结果集映射
<?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.UserDao">
<!--配置user的映射-->
<resultMap id="userMap" type="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<!--配置一对多的映射:封装account-->
<collection property="as" ofType="Account">
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
</mapper>
7.编写相应测试类
一对一(多对一)查询
主要通过映射文件配置resultMap,其它照常编写即可
1.在AccountDao中添加如下代码
/**
* 查找所有account同时查出相应的user,
* @return
*/
List<Account> findAll();
2.在AccountDao.xml添加如下代码
<!-- 配置查询所有的操作 -->
<select id="findAll" resultMap="AccountUserMap">
<!-- 这里引用了抽取的代码块 -->
<include refid="defaultSql"></include>
</select>
3.在测试类中添加如下代码
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
List<Account> as = accountDao.findAll();
for (Account account : as) {
System.out.println("---每个账户的信息---");
System.out.println(account);
System.out.println(account.getUser());
}
}
一对多查询
主要通过映射文件配置resultMap,其它照常编写即可
1.在UserDao中添加如下代码
/**
* 查找所有user,同时查询出对应的account
* @return
*/
List<User> findAll();
2.在UserDao.xml添加如下代码
<!-- 配置查询所有的操作 -->
<select id="findAll" resultMap="userMap">
select u.*, a.id as aid, a.uid, a.money from user u left outer join account a on u.id = a.uid
</select>
3.在测试类中添加如下代码
/**
* 测试查询所有
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for (User u : users) {
System.out.println("---每个用户的信息---");
System.out.println(u);
System.out.println(u.getAs());
}
}
多表查询之多对多
前期准备
具体参考单表的环境搭建,这里只演示新增和修改的部分
1.新建role表,和中间表user_role并插入数据
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`ID` int(11) NOT NULL COMMENT '编号',
`ROLE_NAME` varchar(30) default NULL COMMENT '角色名称',
`ROLE_DESC` varchar(60) default NULL COMMENT '角色描述',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`) values (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`UID` int(11) NOT NULL COMMENT '用户编号',
`RID` int(11) NOT NULL COMMENT '角色编号',
PRIMARY KEY (`UID`,`RID`),
KEY `FK_Reference_10` (`RID`),
CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),
CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user_role`(`UID`,`RID`) values (41,1),(45,1),(41,2);
2.编写Role实体类
public class Role implements Serializable {
private Integer id;
private String roleName;
private String roleDesc;
//多对多关系映射:1个角色可以赋予多个用户
private List<User> users;
......
}
3.编写 Role 持久层接口
public interface RoleDao {
......
}
4.编写Role的映射文件
<?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.RoleDao">
<!--配置role的映射-->
<resultMap id="roleMap" type="Role">
<id property="id" column="rid"></id>
<result property="roleName" column="role_name"></result>
<result property="roleDesc" column="role_desc"></result>
<collection property="users" ofType="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
</collection>
</resultMap>
</mapper>
5.重写User实体类和映射文件,和Role类似,此处省略
6.编写相应的测试类
查询所有role与其对应的user
主要通过映射文件配置resultMap,这里注意SQL语句的编写即可,其它照旧
<!-- 配置查询所有的操作 -->
<select id="findAll" resultMap="userMap">
select u.*, r.id as rid, r.role_name, r.role_desc from user u left outer join user_role ur on u.id = ur.uid left outer join role r on r.id = ur.rid
</select>
查询所有user的方法大致相同,此处省略
延迟加载
在前面一对一、一对多查询的案例的基础上进行演示
一对一(多对一)通常采用立即加载,这里为了演示,采取延迟加载,使用assocation实现
account的持久层接口
public interface AccountDao {
/**
* 查找所有account,同时查询对应的user
* @return
*/
List<Account> findAll();
/**
* 根据uid查找账户
* @return
*/
List<Account> findByUid();
}
account的持久层映射
<?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.AccountDao">
<!--定义封装Account和User的resultMap-->
<resultMap id="AccountMap" type="Account">
<id property="id" column="id"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--配置延迟加载,封装主表实体user-->
<!--
column:传递给select的参数
select:查询的方法
javaType:封装的类型
-->
<association property="user" column="uid" javaType="User" select="com.itheima.dao.UserDao.findById">
</association>
</resultMap>
<!--抽取重复的语句代码片段-->
<sql id="defaultSql">
select * from account
</sql>
<!-- 配置查询所有的操作 -->
<select id="findAll" resultMap="AccountMap">
<include refid="defaultSql"></include>
</select>
<!--根据uid查找账户-->
<select id="findByUid" resultType="Account" parameterType="Integer">
<include refid="defaultSql"></include> where uid = #{uid}
</select>
</mapper>
**一对多关系配置的<collection>结点中配置延迟加载策略 **
user的持久层接口
public interface UserDao {
/**
* 查找所有user,同时查询拥有的使用账户
* @return
*/
List<User> findAll();
/**
* 根据id查找用户
* @param id
* @return
*/
//User findById(Integer id);
}
user的持久层映射
<?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.UserDao">
<!--配置user的映射-->
<resultMap id="userMap" type="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<!--
collection 是用于建立一对多中集合属性的对应关系
ofType 用于指定集合元素的数据类型
select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称)
column 是用于指定使用哪个字段的值作为条件查询
-->
<collection property="as" ofType="Account" select="com.itheima.dao.AccountDao.findByUid" column="id"></collection>
</resultMap>
<!--抽取重复的语句代码片段-->
<sql id="defaultSql">
select * from user
</sql>
<!-- 配置查询所有的操作 -->
<select id="findAll" resultMap="userMap">
<include refid="defaultSql"></include>
</select>
<!--根据id查找用户-->
<select id="findById" parameterType="int" resultType="User">
<include refid="defaultSql"></include>
where id = #{id}
</select>
</mapper>
二级缓存的开启与关闭
第一步:在 SqlMapConfig.xml 文件开启二级缓存
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存。
第二步:配置相关的 Mapper 映射文件
<cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。
<?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.UserDao">
<!-- 开启二级缓存的支持 -->
<cache></cache>
</mapper>
第三步: 配置 <select> 上面的 useCache 属性
<!-- 根据 id 查询 -->
<select id="findById" resultType="user" parameterType="int" useCache="true">
select * from user where id = #{uid}
</select>
将 UserDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。
注意: 针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。
使用注解开发
Mybatis 可以使用注解开发方式 ,这样我们就可以减少编写 Mapper 映射
文件了
mybatis常用注解说明
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
@ResultMap:实现引用@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用
使用前要在SqlMapConfig.xml配置映射信息
<!-- 配置映射信息 -->
<mappers>
<!-- 配置 dao 接口的位置,它有两种方式
第一种:使用 mapper 标签配置 class 属性
第二种:使用 package 标签,直接指定 dao 接口所在的包
-->
<package name="com.itheima.dao"/>
</mappers>
单表crud
不用再编写持久层映射文件,直接在持久层接口使用注解开发
用user表做演示
package com.itheima.dao;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
/**
* user类的持久化操作
*/
public interface UserDao {
/**
* 查询所有user
* @return
*/
@Select("select * from user")
public List<User> findAll();
/**
* 添加user
* @param user
*/
@Insert("insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})")
public void saveUser(User user);
/**
* 更新用户
* @param user
*/
@Update("update user set username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} where id = #{id}")
public void updateUser(User user);
/**
* 删除用户
* @param id
*/
@Delete("delete from user where id = #{id}")
public void deleteUser(Integer id);
/**
* 根据id查询user
* @param id
* @return User
*/
@Select("select * from user where id = #{id}")
public User findById(Integer id);
/**
* 根据id模糊查询
* @param name
* @return List<User>
*/
@Select("select * from user where username like '%${value}%'")
public List<User> findByName(String name);
/**
* 查询user总记录数
* @return int
*/
@Select("select count(*) from user")
public int findTotal();
}
使用注解实现复杂关系映射开发
复杂关系映射的注解说明
@Results 注解
代替的是标签<resultMap>
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(), @Result() })或@Results(@Result())
@Resutl 注解
代替了 <id>标签和<result>标签
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一)
代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。
使用格式:
@Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一)
代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))
使用注解实现一对一和一对多复杂关系映射及延迟加载
用user表和account表做演示
account持久层接口
package com.itheima.dao;
import com.itheima.domain.Account;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;
/**
* account的持久化操作
*/
public interface AccountDao {
/**
* 查询所有account,同时查询所属用户
* @return List<Account>
*/
@Select("select * from account")
@Results(id = "accountMap", value = {
@Result(id = true, property = "id", column = "id"),
@Result(property = "uid", column = "uid"),
@Result(property = "money", column = "money"),
@Result(property = "user", column = "uid", one = @One(select = "com.itheima.dao.UserDao.findById", fetchType = FetchType.EAGER))
})
public List<Account> findAll();
/**
* 根据uid查询
* @param uid
* @return
*/
@Select("select * from account where uid = #{uid}")
public List<Account> findByUid(Integer uid);
}
user持久层接口
package com.itheima.dao;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;
/**
* user类的持久化操作
*/
@CacheNamespace(blocking = true)
public interface UserDao {
/**
* 查询所有user
* @return
*/
@Select("select * from user")
@Results(id = "userMap", value = {
@Result(id = true, property = "userId", column = "id"),
@Result(property = "userName", column = "username"),
@Result(property = "userBirthday", column = "birthday"),
@Result(property = "userSex", column = "sex"),
@Result(property = "userAddress", column = "address"),
@Result(property = "accounts", column = "id", many = @Many(select = "com.itheima.dao.AccountDao.findByUid", fetchType = FetchType.LAZY))
})
public List<User> findAll();
/**
* 根据id查询user
* @param id
* @return User
*/
@Select("select * from user where id = #{id}")
@ResultMap("userMap")
public User findById(Integer id);
}
mybatis 基于注解的二级缓存
在 SqlMapConfig 中开启二级缓存支持
<!-- 配置二级缓存 -->
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
在持久层接口中使用注解配置二级缓存
@CacheNamespace(blocking=true)//mybatis基于注解方式实现配置二级缓存
public interface UserDao {}

mybatis的基本使用
浙公网安备 33010602011771号