一、MyBatis分页插件
1.1 分页插件的介绍
分页是一种将所有数据分段展示给用户的技术.用户每次看到的不是全部数据,而是其中的一部分,如果在其中没有找到自己想要的内容,用户可以通过制定页码或是翻页的方式转换可见内容,直到找到自己想要的内容为止。
分页的的好处:
1.提高性能,一次查20个,比一次查20000个性能肯定更好;另外如果数据量很大,一次性将内容都查询出来,查询出来的结果是放在内存里面的,会增加cpu的开销造成内存的浪费,效率极低。
2.展现层面的考虑:如果一次展现太多的数据,不管是排版,还是美观上都不好。
1.2 分页插件的引入和配置
(1).在pom.xml中引入插件依赖
(2).在mybatis核心配置文件中进行配置
1.3 定义UserMapper接口方法
1.4 配置UserMapper.xml映射文件
1.5 测试分页插件作用
二、MyBatis的注解开发
2.1 注解开发的背景介绍
注解提供了一种简单的方式来实现简单映射语句,而不会引入大量的开销。能够读懂别人写的代码,特别是框架相关的代码。本来可能需要很多配置文件,需要很多逻辑才能实现的内容,就可以使用一个或者多个注解来替代,这样就使得编程更加简洁,代码更加清晰。
2.2 常用注解介绍
这几年来注解开发越来越流行,Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射文件了。
本次我们先围绕一些基本的 CRUD 来学习,再学习复杂映射关系及延迟加载。
@Insert: 实现新增
@Update: 实现更新
@Delete: 实现删除
@Select: 实现查询
@Result: 实现结果集封装
@Results: 这个注解用于定义结果集映射,它包含了一个或多个 @Result 注解,每个 @Result 注解指定了一个数据库字段到 Java 对象属性的映射
@ResultMap: 实现引用 @Results 定义的封装
@One: 实现一对一结果集封装
@Many: 实现一对多结果集封装
@CacheNamespace: 在类名上加入注解,实现注解二级缓存的使用
三、项目环境搭建
3.1 构建maven工程,导入依赖
3.2 加入配置文件
加入mybatis核心配置文件,log4j.properties配置文件、db.properties配置文件、MybatisUtil.java工具类,加入到项目中
四、使用 Mybatis 注解实现基本 CRUD
4.1 编写实体类
package com.sy.pojo; import java.io.Serializable; import java.util.List; public class User implements Serializable { private int id; //编号id private String username; //用户名 private String password; //密码 private int age; //年龄 private String sex; //性别 private String email; //邮箱 private List<Order> orderList; public List<Order> getOrderList() { return orderList; } public void setOrderList(List<Order> orderList) { this.orderList = orderList; } public User() { } public User(String username, String password, int age, String sex, String email) { this.username = username; this.password = password; this.age = age; this.sex = sex; this.email = email; } public User(int id, String username, String password, int age, String sex, String email) { this.id = id; this.username = username; this.password = password; this.age = age; this.sex = sex; this.email = email; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", age=" + age + ", sex='" + sex + '\'' + ", email='" + email + '\'' + ", orderList=" + orderList + '}'; } }package com.sy.pojo; public class Order { // 订单id private Integer id; // 用户id,该属性名和数据库的字段名不一致 private Integer userId; // 订单号 private String number; // 订单创建时间 private String createTime; // 备注 private String note; private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Order() { } public Order(Integer userId, String number, String createTime, String note) { this.userId = userId; this.number = number; this.createTime = createTime; this.note = note; } public Order(Integer id, Integer userId, String number, String createTime, String note) { this.id = id; this.userId = userId; this.number = number; this.createTime = createTime; this.note = note; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } @Override public String toString() { return "Order{" + "id=" + id + ", userId=" + userId + ", number='" + number + '\'' + ", createTime='" + createTime + '\'' + ", note='" + note + '\'' + ", user=" + user + '}'; } }4.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> <!-- SqlMapConfig.xml 中配置的内容和顺序如下: 1. properties(属性) 2. settings(全局配置参数) 3. typeAliases(类型别名) 4. plugins(插件) 5. environments(环境集合属性对象) ==environment(环境子属性对象) ====transactionManager(事务管理) ======dataSource(数据源) 6. mappers(映射器) --> <!--引入数据源 db.properties文件 用resource属性加载外部配置文件 --> <properties resource="db.properties"></properties> <!--配置使用的日志--> <settings> <!-- 配置使用的日志: value="STDOUT_LOGGING":mybatis自带的日志输出 value="log4j": 当然也可以设置为log4j --> <setting name="logImpl" value="log4j"/> <!--依赖包的问题:空指针异常--> <!-- 全局开启延迟加载 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 当启用时,有会话时,会执行延迟加载 --> <setting name="aggressiveLazyLoading" value="false"/> <!-- 开启二级缓存的支持 --> <setting name="cacheEnabled" value="true"/> </settings> <!--设置别名 typeAliases类型别名--> <typeAliases> <!--别名定义:针对单个别名定义 type:类型的路径; alias:别名--> <!--可以为多个实体类配置别名 别名的大小写没有影响--> <!--<typeAlias type="com.sy.pojo.User" alias="user"/>--> <!-- 批量别名的定义: (常用) package:指定包名,mybatis会自动扫描包中的pojo类, 自动定义别名,别名就是类名(首字母大写或小写都可以) --> <!--扫描包 的方式--> <package name="com.sy.pojo"/> </typeAliases> <!--分页插件--> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins> <!-- environments:设置多个连接数据库的环境 属性: default:设置默认使用的环境的id(development代表开发环境下) --> <environments default="development"> <!-- environment:设置具体的连接数据库的环境信息 属性: id:设置环境的唯一标识,可通过environments标签中的 default设置某一个环境的id,表示默认使用的环境 --> <environment id="development"> <!-- transactionManager:设置事务管理方式 属性: type:设置事务管理方式,type="JDBC|MANAGED" type="JDBC":说明当前mybatis事务管理使用的是connection的机制,connection.commit().connection.rollback()等 type="MANAGED":mybatis不管理事务了,交给其他外部第三方框架管理,比如和Spring整合之后交给Spring管理 --> <transactionManager type="JDBC"/> <!-- dataSource:设置数据源 属性: type:设置数据源的类型,type="POOLED|UNPOOLED|JNDI" type="POOLED":使用POOLED连接池,这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 type="UNPOOLED":不使用数据库连接池,即每次使用连接都需要重新创建 type="JNDI":调用上下文中的数据源 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> <environment id="test"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> <!--在xml文件中用& 在properties文件中用&--> </environments> <!--加载映射文件--> <mappers> <!--包扫描 要求:mapper接口名称和mapper映射文件名称相同--> <package name="com.sy.mapper"/> </mappers> </configuration>4.3 使用注解方式开发持久层接口
package com.sy.mapper; import com.sy.pojo.Order; import com.sy.pojo.User; import org.apache.ibatis.annotations.*; import org.apache.ibatis.mapping.FetchType; import java.util.List; //开启二级缓存的支持 @CacheNamespace public interface OrderMapper { /** * 查询所有订单 */ @Results(id = "orderResult",value = { @Result(id = true,column = "id",property = "id"), @Result(column = "user_id",property = "userId"), @Result(column = "number",property = "number"), @Result(column = "create_time",property = "createTime"), @Result(column = "note",property = "note"), }) @Select("select * from orders") List<Order> queryOrderList(); /** * 根据用户id查询订单 */ @ResultMap(value = "orderResult") @Select("select * from orders where user_id = #{uid}") List<Order> queryOrderByUid(Integer uid); /** * 添加订单信息 @SelectKey注解: 则用于定义一个查询,这个查询通常是用来获取最后插入的记录的ID * 属性: * statement属性: 用于指定查询最后生成的主键值的SQL语句 * keyProperty属性: 用于指定将获取到的主键值赋值给哪个属性 * keyColumn属性: 表示将查询结果赋值给数据表中的哪一列 * before属性: 用于指定在插入数据之前还是之后执行这个查询 * resultType属性: 用于指定查询返回的结果类型 * LAST_INSERT_ID()是MySQL特有的函数,用于获取最后一次插入生成的自增ID */ @Insert("insert into orders ( user_id, number, create_time, note)" + "values (#{userId},#{number},#{createTime},#{note})") @SelectKey(statement = "SELECT LAST_INSERT_ID()", before = false, keyColumn = "id", keyProperty = "id", resultType = Integer.class) Integer addOrder(Order order); /** * 修改订单信息 * */ @Update("update orders set number = #{number},note = #{note} where id = #{id}") Integer updateOrderById(Order order); /** * 删除订单信息 */ @Delete("delete from orders where id = #{id}") Integer deleteOrderById(Integer id); //需求:查询每个订单对应的用户信息(嵌套查询) @Results(value = { //订单信息 @Result(id = true,column = "id",property = "id"), @Result(column = "user_id",property = "userId"), @Result(column = "number",property = "number"), @Result(column = "create_time",property = "createTime"), @Result(column = "note",property = "note"), //用户信息 @Result(property = "user",javaType = User.class,column = "user_id", one=@One(select = "com.sy.mapper.UserMapper.queryById",fetchType = FetchType.LAZY) ) }) @Select("select * from orders") List<Order> queryOrderUser(); }4.4 编写测试方法
package com.sy.test; import com.sy.mapper.OrderMapper; import com.sy.pojo.Order; import com.sy.utils.MyBatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import java.util.List; public class OrderMapperTest { //查询所有订单 @Test public void queryOrderListTest(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); OrderMapper mapper = sqlSession.getMapper(OrderMapper.class); List<Order> orders = mapper.queryOrderList(); for (Order order : orders) { System.out.println(order); } MyBatisUtils.close(sqlSession); } //根据用户id查询订单 @Test public void queryOrderByUidTest(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); OrderMapper mapper = sqlSession.getMapper(OrderMapper.class); List<Order> orders = mapper.queryOrderByUid(1); for (Order order : orders) { System.out.println(order); } MyBatisUtils.close(sqlSession); } //添加订单信息 @Test public void addOrderTest(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); OrderMapper mapper = sqlSession.getMapper(OrderMapper.class); Order order = new Order(3, "1000014", "2015-02-12 16:13:25", "新增订单"); int i = mapper.addOrder(order); if (i > 0){ System.out.println("更新了: " + i + " 条数据"); } System.out.println(order); MyBatisUtils.close(sqlSession); } // 修改订单信息 @Test public void updateOrderByIdTest(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); OrderMapper mapper = sqlSession.getMapper(OrderMapper.class); Order order = new Order(); order.setId(6); order.setNumber("1000015"); order.setNote("修改订单"); int i = mapper.updateOrderById(order); if (i > 0){ System.out.println("修改成功"); } MyBatisUtils.close(sqlSession); } //删除订单信息 @Test public void deleteOrderByIdTest(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); OrderMapper mapper = sqlSession.getMapper(OrderMapper.class); Integer i = mapper.deleteOrderById(4); if (i > 0){ System.out.println("删除成功"); } MyBatisUtils.close(sqlSession); } //需求:查询每个订单对应的用户信息(嵌套查询) @Test public void queryOrderUserTest(){ SqlSession sqlSession = MyBatisUtils.getSqlSession(); OrderMapper mapper = sqlSession.getMapper(OrderMapper.class); List<Order> orders = mapper.queryOrderUser(); for (Order order : orders) { System.out.println(order); } MyBatisUtils.close(sqlSession); } }五、使用注解实现复杂关系映射开发
5.1 复杂关系映射的注解介绍
1. @Results 注解:
代替的是标签<resultMap>
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(),@Result()})或@Results(@Result())
2. @Resutl 注解:
代替了 <id> 标签和<result> 标签
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
3. @One 注解(一对一)
代替了<assocation> 标签,是多表查询的关键,在注解中用来指定子查询返回单一对
象。
@One 注解属性介绍:
select 指定用的 来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。
使用格式:
@Result(column=" ",property="",one=@One(select=""))
4. @Many 注解(一对多)
代替了<Collection> 标签, 是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))
5.2 使用注解实现一对一复杂关系映射及延迟加载
需求:查询每个订单对应的用户信息