MyBatis笔记09 注解开发
coconutnut

https://www.bilibili.com/video/BV1Db411s7F5

P68~75

环境搭建

导坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<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>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>

准备实体类和接口

1
2
3
4
5
6
7
8
9
10
11
public class User implements Serializable{

private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;

// get set ...

}
1
2
3
4
5
public interface IUserDao {

// ...

}

配置文件

映射配置文件可以不要了,但主配置文件不能省略

(如果使用注解开发,但相应路径下存在对应的xml,不管用不用都会报错)

SqlMapConfig.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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 resource="jdbcConfig.properties"></properties>
<!--配置别名-->
<typeAliases>
<package name="com.itheima.domain"></package>
</typeAliases>
<!-- 配置环境-->
<environments default="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>
<!-- 指定带有注解的dao接口所在位置 -->
<mappers>
<package name="com.itheima.dao"></package>
</mappers>
</configuration>

jdbcConfig.properties中配置数据库连接信息

1
2
3
4
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy_mybatis
jdbc.username=root
jdbc.password=1234

单表CRUD

在mybatis中针对CRUD共有四个注解:@Select @Insert @Update @Delete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public interface IUserDao {

// 增
@Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);

// 删
@Delete("delete from user where id=#{id} ")
void deleteUser(Integer userId);

// 改
@Update("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}")
void updateUser(User user);

// 查
@Select("select * from user")
List<User> findAll();

@Select("select * from user where id=#{id} ")
User findById(Integer userId);

// 方法一:这里#{username}没有%,查询时要传入如“%王%”
@Select("select * from user where username like #{username} ")
// 方法二:${}中固定写value,传参时不用写%
@Select("select * from user where username like '%${value}%' ")
List<User> findUserByName(String username);
// 区别和之前一样,一个是字符串拼接,一个是参数占位符

@Select("select count(*) from user ")
int findTotalUser();

}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class AnnotationCRUDTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;

@Before
public void init()throws Exception{
// 1.获取字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
// 2.根据字节输入流构建SqlSessionFactory
factory = new SqlSessionFactoryBuilder().build(in);
// 3.根据SqlSessionFactory生产一个SqlSession
session = factory.openSession();
// 4.使用SqlSession获取Dao的代理对象
userDao = session.getMapper(IUserDao.class);
}

@After
public void destroy()throws Exception{
// 提交
session.commit();
// 释放资源
session.close();
in.close();
}

@Test
public void testSave(){
User user = new User();
user.setUsername("mybatis annotation");
user.setAddress("北京市昌平区");

userDao.saveUser(user);
}

// ...
}

实体类属性和数据库不对应问题

实体类中名称和表中对不上时(userName & username)

1
2
3
4
5
6
7
8
9
public class User implements Serializable{

private Integer userId;
private String userName;
private String userAddress;
private String userSex;
private Date userBirthday;

}

可以使用别名,但是所有位置都要使用别名,比较麻烦

可以使用@Results注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface IUserDao {

@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday")
})
List<User> findAll();

@Select("select * from user where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);
}

主键:id=true

其它位置用@ResultMap引用

标准写法@ResultMap(value={“userMap”})

由于只有一个属性,value可以省略;数组中只有一个元素,{}可以省略

于是可以直接写@ResultMap(“userMap”)

多表查询

实体类和接口

再建一个账户

1
2
3
4
5
6
7
8
9
10
11
12
public class Account implements Serializable {

private Integer id;
private Integer uid;
private Double money;

//多对一(mybatis中称为一对一)的映射:一个账户只能属于一个用户
private User user;

// get set ...

}

修改用户实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class User implements Serializable{

private Integer userId;
private String userName;
private String userAddress;
private String userSex;
private Date userBirthday;

//一对多关系映射:一个用户对应多个账户
private List<Account> accounts;

// get set ...

}

一对一查询

查账户以及所属的用户

IAccountDao中

1
2
3
4
5
6
7
8
 	@Select("select * from account")
@Results(id="accountMap",value = {
@Result(id=true,column = "id",property = "id"),
@Result(column = "uid",property = "uid"),
@Result(column = "money",property = "money"),
@Result(property = "user",column = "uid",one=@One(select="com.itheima.dao.IUserDao.findById",fetchType= FetchType.EAGER))
})
List<Account> findAll();

这里不使用left outer join,使用@One

select要找到能实现功能的方法,即IUserDao中findById,来查询账户所属的用户

FetchType可以配置延迟加载(LAZY),或立即加载(EAGER)

实际开发时对一一般选择立即加载,对多一般选择延迟加载

一对多查询

查一个用户,和该用户对应的多个账户

IUserDao中

1
2
3
4
5
6
7
8
9
10
11
12
@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday"),
@Result(property = "accounts",column = "id",
many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
List<User> findAll();

用@Many

IAccountDao中加一个方法

1
2
@Select("select * from account where uid = #{userId}")
List<Account> findAccountByUid(Integer userId);

缓存配置

不管用xml还是注解,一级缓存默认都是开的

打开二级注解,全局配置默认也是打开

对于单个类,使用@CacheNamespace(默认是false)

1
2
3
4
@CacheNamespace(blocking = true)
public interface IUserDao {
// ...
}

即可开启二级缓存