对应工程为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 * 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 * from user")
List<User> findAll();
("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);
("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}")
void updateUser(User user);
("delete from user where id=#{id} ")
void deleteUser(Integer userId);
("select * from user where id=#{id} ")
User findById(Integer userId);
// @Select("select * from user where username like #{username} ")
("select * from user where username like '%${value}%' ")
List<User> findUserByName(String username);
("select count(*) from user ")
int findTotalUser();
}
测试类:
public class AnnotationCRUDTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IUserDao userDao;
public void init()throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
session = factory.openSession();
userDao = session.getMapper(IUserDao.class);
}
public void destroy()throws Exception{
session.commit();
session.close();
in.close();
}
public void testSave(){
User user = new User();
user.setUsername("黎佳琪");
user.setAddress("北京市黄陂镇");
userDao.saveUser(user);
}
public void testUpdate(){
User user = new User();
user.setId(10);
user.setUsername("李佳琪");
user.setAddress("广州市海淀区");
user.setSex("男");
user.setBirthday(new Date());
userDao.updateUser(user);
}
public void testDelete(){
userDao.deleteUser(11);
}
public void testFindOne(){
User user = userDao.findById(10);
System.out.println(user);
}
public void testFindByName(){
// List<User> users = userDao.findUserByName("%佳琪%");
List<User> users = userDao.findUserByName("佳琪");
for(User user : users){
System.out.println(user);
}
}
public void testFindTotal(){
int total = userDao.findTotalUser();
System.out.println(total);
}
}
1.3@Results起别名注解
当用户实体类的属性和数据库的列名不一致的时候,需要配置,@Results的功能相当于xml的resultMap,其中设置id = "userMap"
方便其他代码可以引用这个结果集封装,如下:
"select * from user ")(
(id = "userMap",value = {
(id = true,column ="id",property = "userid"),
( column ="username",property = "userName"),
( column ="address",property = "useraddress"),
( column ="sex",property = "usersex"),
( column ="birthday",property = "userbirthday")
})
public List<User> finAll();
("select * from user where id = #{id}")
(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 * from account01")(
(id = "accountMap", value = {
(id = true, column = "id", property = "id"),
(column = "uid", property = "uid"),
(column = "money", property = "money"),
//此处配置对应关系
(property = "user", column = "uid",
one = (select = "cn.smm.dao.IUserDao.findById",
fetchType = FetchType.EAGER))
})
public List<Account> findAll();
在@Results中前三行是建立起别名关系,下一句的对应一对一的查询关系,即一个账户对应一个用户,此处为查一,使用立即加载。
property = "user", column = "uid", one = (select = "cn.smm.dao.IUserDao.findById", fetchType = FetchType.EAGER))(
property :选择要查询哪个实体类,user为Account实体类中的属性private User user;
column :使用哪个字段去查
@One:select:选择要查询的接口的全限定类名,并制定相应的方法
fetchType :有三个LAZY(延迟加载),EAGER(立即加载),DEFAULT
测试类:
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接口
(property = "accounts", column = "id",
many = (select = "com.itcast.dao.IAccountDao.findAccountById",
fetchType = FetchType.LAZY))
//IAccountDao接口
("select * from account01 where uid = #{uid}")
public List<Account> findAccountById(Integer id);
测试类:
public void findAllTest() {
List<User> users = userDao.finAll();
for (User user : users) {
System.out.println(user);
System.out.println(user.getAccounts());
}
}
//懒加载测试类
public void findAllTest() {
List<User> users = userDao.finAll();}
3.二级缓存@CacheNamespace
首先测试一级缓存
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);
}
输出结果:
首先在主配置文件中打开全局二级缓存支持。
<configuration>
<!--开启全局二级缓存-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
然后是对要测试的接口开启二级缓存,这里选用IUserDao。
//开启二级缓存
(blocking = true)
public interface IUserDao {
二级缓存测试类:
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);
}
输出结果:只是查询了一次,并且两次是不一样的。
3.1二级缓存注意事项
当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化方式来保存对象。