Mybatis注解开发
1.Mybaits常用注解说明
@Insert:实现新增
@Select:实现查询
@Update:实现更新
@Delete:实现删除
@Result:实现结果集的封装
@Results:可以与Result一起使用,实现多个结果集的封装
@ResultMap:实现引用@Results定义的封装
@One:实现一对一结果集的封装
@Many:实现一对多结果集的封装
@SelectProvider:实现动态SQL映射
@CacheNamespace:实现注解二级缓存的使用
1.1 使用Mybatis注解实现基本CRUD
package com.llb.domain; import java.io.Serializable; import java.util.Date; /** * Ceate By llb on 2019/8/9 */
public class User implements Serializable{ private Integer userId; private String userName; private String userAddress; private String userSex; private Date userBirthday; }
此处故意与数据库列名不一致
1.2 使用注解方式开发持久层接口
package com.llb.dao; import com.llb.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; /** * 针对crud有四个注解 * @Select, @Insert, @Update, @Delete * Ceate By llb on 2019/8/9 */
public interface UserMapper { /** * 查询所有用户 * @return
*/ @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}, address = #{address}, sex= #{sex}, birthday = #{birthday} where id = #{id}") void updateUser(User user); /** * 删除用户 */ @Delete("delete from user where id = #{id}") void deleteUser(Integer id); /** * 根据id查询用户 */ @Select("select * from user where id = #{id}") User findUserById(Integer id); /** * 根据姓名模糊查询 */
// @Select("select * from user where username like #{username}")
@Select("select * from user where username like '%${value}%'") List<User> findUserByUsername(String username); /** * 查询总用户数量 */ @Select("select count(*) from user") Integer findTotal(); }
通过此注解方式,我们就不需要再去编写UserMapper.xml映射文件了
1.3 编写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 resource="jdbcConfig.properties"></properties>
<!--配置别名-->
<typeAliases>
<package name="com.llb.domain"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!--配置MySQl环境-->
<environment id="mysql">
<!--配置事务类型为JDBC-->
<transactionManager type="JDBC"></transactionManager>
<!--配置数据源-->
<!--POOLED创建连接池-->
<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>
<!-- 配置 dao 接口的位置,它有两种方式 第一种:使用 mapper 标签配置 class 属性 第二种:使用 package 标签,直接指定 mapper 接口所在的包 -->
<!--<mapper class="com.llb.dao.UserMapper"></mapper>-->
<package name="com.llb.dao"></package>
</mappers>
</configuration>
1.4 编写测试方法
package com.llb.test; /** * Ceate By llb on 2019/8/9 */
public class AnnotationCRUD { InputStream in ; SqlSessionFactory factory; SqlSession sqlSession; UserMapper mapper; @Before public void init() throws IOException { in = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(in); sqlSession = factory.openSession(); mapper = sqlSession.getMapper(UserMapper.class); } @After public void destroy() throws IOException { sqlSession.commit(); sqlSession.close(); in.close(); } /** * 测试注解保存用户 */ @Test public void testInsert(){ User user = new User(); user.setUsername("王五"); user.setAddress("浙江杭州"); user.setSex("男"); user.setBirthday(new Date()); mapper.saveUser(user); } /** * 测试注解修改用户 */ @Test public void testUpdate(){ User user = new User(); user.setId(53); user.setUsername("王五"); user.setAddress("浙江杭州"); user.setSex("男"); user.setBirthday(new Date()); mapper.updateUser(user); } /** * 测试注解删除用户 */ @Test public void testDelete(){ mapper.deleteUser(53); } /** * 根据id查询用户 */ @Test public void testFindUserById(){ User user = mapper.findUserById(41); System.out.println(user); } /** * 根据姓名模糊查询用户 */ @Test public void testFindUserByName(){ List<User> users = mapper.findUserByUsername("%张%"); for (User user: users) { System.out.println(user); } } /** * 总条数 */ @Test public void findTotal(){ Integer total = mapper.findTotal(); System.out.println(total); } }
源码直达:github
2 使用注解实现复杂关系映射开发
实现复杂关系映射开发之前我们可以在映射文件中通过配置<resultMap>来实现,在使用注解开发时,我们需要借助@Result、@Results、@One、@Many
2.1 复杂关系映射的注解说明
@Results 注解 代替的标签是<resultMap> 该注解中可以使用单个@Result,也可以使用@Results集合 @Results({@Result(),@Result()})或@Results(@Result())
@Result注解
代替了<id>和<result>标签
@Result中的属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用@One注解(@Result(one = @One()))
many 需要使用@Many注解(@Result(many = @Many()))
@One注解(一对一)
代替了<association>标签,是表查询的关键,在注解中用来指定子查询返回单一对象。
属性介绍:
select 指定用来多表查询的SqlMapper
fetchType 会覆盖全局的配置参数lazyLoadingEnabled。
使用格式:
@Result(column="", prperty="", one=@One(select=""))
@Many注解(一对多)
代替了<collection>标签,是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))
2.2 使用注解实现一对一复杂关系映射延迟加载
需求:
加载账户信息时并且加载该账户的用户信息,根据情况可实现延迟加载。(注解方式)
2.2.1 添加User实体类及Account实体类
用户实体类:
package com.llb.domain; import java.io.Serializable; import java.util.Date; import java.util.List; /** * Ceate By llb on 2019/8/9 */
public class User implements Serializable { private Integer userId; private String userName; private String userAddress; private String userSex; private Date userBirthday; }
账户实体类:
package com.llb.domain; import java.io.Serializable; /** * 账户的实体类 * Ceate By llb on 2019/8/7 */
public class Account implements Serializable { private Integer id; private Integer uid; private double money; //从表实体应该包含一个主表实体的对象引用
private User user; }
2.2.2 添加账户的持久层接口并使用注解配置
package com.llb.dao;import java.util.List; /** * Ceate By llb on 2019/8/7 */
public interface AccountMapper { /** * 多对一:立即加载 * 查询账户所对应的的用户 * FetchType.EAGER:立即加载 * */ @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(column = "uid", property = "user", one = @One(select = "com.llb.dao.UserMapper.findUserById", fetchType = FetchType.EAGER)), }) List<Account> findAllAccount(); }
2.2.3 测试一对一关联及延迟加载
package com.llb.test; /** * Ceate By llb on 2019/8/9 */
public class AccountCRUD { InputStream in ; SqlSessionFactory factory; SqlSession sqlSession; AccountMapper mapper; @Before public void init() throws IOException { in = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(in); sqlSession = factory.openSession(); mapper = sqlSession.getMapper(AccountMapper.class); } @After public void destroy() throws IOException { sqlSession.commit(); sqlSession.close(); in.close(); } /** * 查询账户所对应的用户 */ @Test public void findAllAccount(){ List<Account> accounts = mapper.findAllAccount(); for (Account account: accounts) { System.out.println(account); } } }
3. 使用注解实现一对多复杂关系映射
需求:查询用户信息时,也要查询他的账户列表。使用注解方式实现。
分析:一个用户具有多个账户信息,所以形成了用户(User)与账户(Account)之间的一对多关系。
3.1 User实体类加入List<Account>
package com.llb.domain; import java.io.Serializable; import java.util.Date; import java.util.List; /** * Ceate By llb on 2019/8/9 */
public class User implements Serializable { private Integer userId; private String userName; private String userAddress; private String userSex; private Date userBirthday; //一对多关系映射:主表方法应该包含一个从表方的集合引用
private List<Account> accounts; }
3.2 编写用户的持久层接口并使用注解配置
package com.llb.dao; import com.llb.domain.User; import org.apache.ibatis.annotations.*; import org.apache.ibatis.mapping.FetchType; import java.util.List; /** * 针对crud有四个注解 * @Select, @Insert, @Update, @Delete * Ceate By llb on 2019/8/9 */
//开启二级缓存
@CacheNamespace(blocking = true) public interface UserMapper { /** * 查询所有用户 * @return
*/ @Select("select * from user") @Results(id = "userMap", value ={ @Result(column = "id", property = "userId"), @Result(column = "username", property = "userName"), @Result(column = "sex", property = "userSex"), @Result(column = "birthday", property = "userBirthday"), @Result(column = "address", property = "userAddress"), @Result(column = "id", property = "accounts", many = @Many(select = "com.llb.dao.AccountMapper.findAccountByUid", fetchType = FetchType.LAZY) ) }) List<User> findAll(); /** * 根据id查询用户 */ @Select("select * from user where id = #{id}") @ResultMap(value = {"userMap"}) User findUserById(Integer id); /** * 根据姓名模糊查询 */
// @Select("select * from user where username like #{username}")
@Select("select * from user where username like '%${value}%'") List<User> findUserByUsername(String username); }
3.3 编写账户的持久层接口并使用注解配置
package com.llb.dao; import com.llb.domain.Account; import org.apache.ibatis.annotations.One; import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.mapping.FetchType; import java.util.List; /** * Ceate By llb on 2019/8/7 */
public interface AccountMapper { /** * 根据用户id查询账户 * @return
*/ @Select("select * from account where uid = #{uid}") List<Account> findAccountByUid(Integer uid); }
3.4 添加测试方法
package com.llb.test; /** * Ceate By llb on 2019/8/9 */
public class AnnotationCRUD { InputStream in ; SqlSessionFactory factory; SqlSession sqlSession; UserMapper mapper; @Before public void init() throws IOException { in = Resources.getResourceAsStream("SqlMapConfig.xml"); factory = new SqlSessionFactoryBuilder().build(in); sqlSession = factory.openSession(); mapper = sqlSession.getMapper(UserMapper.class); } @After public void destroy() throws IOException { sqlSession.commit(); sqlSession.close(); in.close(); } /** * 查询所有 */ @Test public void testFindAll(){ List<User> users = mapper.findAll(); for (User user:users) { System.out.println(user); } } }
源码地址:github
4. 注解实现延迟加载