对应工程为mybatis-annotation,mybatis-anno-oneToMany


目录:



1.常用注解

@Insert:实现新增

@Update:实现更新

@Delete:实现删除

@Select:实现查询

@Result:实现结果集封装,里面的id值为true表明主键,默认false;

@Results:可以与@Result 一起使用,封装多个结果集,相当于xml的resultMap。

@ResultMap:实现引用@Results 定义的封装

@One:实现一对一结果集封装

@Many:实现一对多结果集封装

@SelectProvider: 实现动态 SQL 映射

@CacheNamespace:实现注解二级缓存的使用

1.1xml和注解对比

原来的xml的dao配置文件:

<mapper namespace="cn.smm.dao.IUserDao">
<select id="findAll" resultType="cn.smm.domain.User">
select * from user
</select>

在dao接口文件中使用注解:

package cn.smm.dao;

public interface IUserDao {
@Select("select * from user")
List<User> findAll();
}

原配置文件使用namespace和id来指定接口的方法所在位置,而注解直接是注明在方法上面,就可以获取其全限定类名,并且基于value为sql语句,返回值在方法前面已经说明为List,而原配置文件为使用resultType。注意事项:xml和注解只能选其中一种,不然会报错

1.2代码

主配置文件SQLMapConfig:

<?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="cn.smm.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>
<mapper class="cn.smm.dao.IUserDao"></mapper>
</mappers>
</configuration>

用户实体类:

public class User implements Serializable{
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;

IUserDao接口代码:

public interface IUserDao {

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

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

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

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

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

// @Select("select * from user where username like #{username} ")
@Select("select * from user where username like '%${value}%' ")
List<User> findUserByName(String username);

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

测试类:


public class AnnotationCRUDTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;

@Before
public void init()throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
session = factory.openSession();
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("黎佳琪");
user.setAddress("北京市黄陂镇");

userDao.saveUser(user);
}

@Test
public void testUpdate(){
User user = new User();
user.setId(10);
user.setUsername("李佳琪");
user.setAddress("广州市海淀区");
user.setSex("男");
user.setBirthday(new Date());

userDao.updateUser(user);
}

@Test
public void testDelete(){
userDao.deleteUser(11);
}

@Test
public void testFindOne(){
User user = userDao.findById(10);
System.out.println(user);
}

@Test
public void testFindByName(){
// List<User> users = userDao.findUserByName("%佳琪%");
List<User> users = userDao.findUserByName("佳琪");
for(User user : users){
System.out.println(user);
}
}

@Test
public void testFindTotal(){
int total = userDao.findTotalUser();
System.out.println(total);
}
}

1.3@Results起别名注解

当用户实体类的属性和数据库的列名不一致的时候,需要配置,@Results的功能相当于xml的resultMap,其中设置​​id = "userMap"​​方便其他代码可以引用这个结果集封装,如下:

    @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")
})
public List<User> finAll();

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

2.案例

2.1一对一查询@One

添加一个账户实体类:

public class Account implements Serializable {
private Integer uid;
private Integer id;
private Double money;
private User user;

添加一个账户接口:

    @Select("select * from account01")
@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 = "cn.smm.dao.IUserDao.findById",
fetchType = FetchType.EAGER))
})
public List<Account> findAll();

在@Results中前三行是建立起别名关系,下一句的对应一对一的查询关系,即一个账户对应一个用户,此处为查一,使用立即加载。

@Result(property = "user", column = "uid", one = @One(select = "cn.smm.dao.IUserDao.findById", fetchType = FetchType.EAGER))

property :选择要查询哪个实体类,user为Account实体类中的属性​​private User user;​

column :使用哪个字段去查

@One:select:选择要查询的接口的全限定类名,并制定相应的方法

fetchType :有三个LAZY(延迟加载),EAGER(立即加载),DEFAULT

测试类:

    @Test
public void findAllTest() {
List<Account> accounts = accountDao.findAll();
for (Account account : accounts) {
System.out.println("---------这是一个账户----------");
System.out.println(account);
System.out.println(account.getUser());
}
}

2.2一对多查询@Many

实体类用户中添加属性:​​private List<Account> accounts;​

同样的在IUserDao接口中的finAll()方法添加相应的注解,(注:accounts为实体类User中的属性private List accounts,且此处为使用many,且需要在IAccountDao接口中添加一个对应的方法findAccountById(),使用延迟加载)。如下:

//IUserDao接口
@Result(property = "accounts", column = "id",
many = @Many(select = "com.itcast.dao.IAccountDao.findAccountById",
fetchType = FetchType.LAZY))

//IAccountDao接口
@Select("select * from account01 where uid = #{uid}")
public List<Account> findAccountById(Integer id);

测试类:

    @Test
public void findAllTest() {
List<User> users = userDao.finAll();
for (User user : users) {
System.out.println(user);
System.out.println(user.getAccounts());
}
}
//懒加载测试类
@Test
public void findAllTest() {
List<User> users = userDao.finAll();}

3.二级缓存@CacheNamespace

首先测试一级缓存

    @Test
public void findByIdTest() {
User user = userDao.findById(10);
System.out.println(user);

User user1 = userDao.findById(10);
System.out.println(user1);
System.out.println(user==user1);
}

输出结果:

6.Mybatis框架学习笔记之注解开发入门、一对多、二级缓存_二级缓存

首先在主配置文件中打开全局二级缓存支持。

<configuration>
<!--开启全局二级缓存-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>

然后是对要测试的接口开启二级缓存,这里选用IUserDao。

//开启二级缓存
@CacheNamespace(blocking = true)
public interface IUserDao {

二级缓存测试类:

    @Test
public void findByIdTest() {
User user = userDao.findById(10);
System.out.println(user);
sqlSession.close();//释放一级缓存

sqlSession = factory.openSession(true);//再次打开session
userDao = sqlSession.getMapper(IUserDao.class);
User user1 = userDao.findById(10);
System.out.println(user1);
System.out.println(user==user1);
}

输出结果:只是查询了一次,并且两次是不一样的。

6.Mybatis框架学习笔记之注解开发入门、一对多、二级缓存_sql_02

3.1二级缓存注意事项

当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化方式来保存对象。