mybatis笔记
# Mybatis 入门
1.创建demo类
public class User implements Serializable {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
}
2.创建SqlMapConfig.xml(src)
<?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>
<!-- 配置mybatis的环境信息 -->
<environments default="development">
<environment id="development">
<!-- 配置JDBC事务控制,由mybatis进行管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源,采用dbcp连接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
3.映射文件
在classpath下,创建sqlmap文件夹。在com.zh.sqlmap目录下,创建User.xml映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
namespace:命名空间,它的作用就是对SQL进行分类化管理,可以理解为SQL隔离
注意:使用mapper代理开发时,namespace有特殊且重要的作用
-->
<mapper namespace="test">
<!--
[id]:statement的id,要求在命名空间内唯一
[parameterType]:入参的java类型
[resultType]:查询出的单条结果集对应的java类型
[#{}]: 表示一个占位符?
[#{id}]:表示该占位符待接收参数的名称为id。注意:如果参数为简单类型时,#{}里面的参数名称可以是任意定义
-->
<select id="findUserById" parameterType="int" resultType="com.zh.demol.User">
SELECT * FROM USER WHERE id = #{id}
</select>
</mapper>
4.配置文件加载映射文件
<!-- 加在配置文件 SqlMapConfig.xml(src)-->
<mappers>
<mapper resource="com/zh/sqlmap/User.xml"></mapper>
</mappers>
5.测试类
public class demo01 {
@Test
public void test1() throws IOException {
//1.读取配置文件
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂。
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过SqlSessionFactory创建SqlSession。
SqlSession session = sessionFactory.openSession();
//4.调用SqlSession的操作数据库方法。
User user = session.selectOne("findUserById",10);
System.out.println(user);
//5.关闭session
session.close();
}
}
User [id=10, username=张三, sex=1, birthday=Thu Jul 10 00:00:00 CST 2014, address=北京市]
# Mybatis CRUD
1.模糊查询用户信息
<!--
[${}]:表示拼接SQL字符串
[${value}]:表示要拼接的是简单类型参数。
注意:
1、如果参数为简单类型时,${}里面的参数名称必须为value
2、${}会引起SQL注入,一般情况下不推荐使用。但是有些场景必须使用${},比如order by ${colname}
-->
<select id="findUserByName" parameterType="String" resultType="com.zh.demol.User">
SELECT * FROM user WHERE username LIKE '%${value}%'
</select>
java代码
//调用模糊查询方法
List<User> users = session.selectList("findUserByName","张");
System.out.println(users);
输出结果
[User [id=10, username=张三, sex=1, birthday=Thu Jul 10 00:00:00 CST 2014, address=北京市], User [id=16, username=张小明, sex=1, birthday=null, address=河南郑州], User [id=24, username=张三丰, sex=1, birthday=null, address=河南郑州]]
2.插入用户信息
<!-- 插入用户 -->
<insert id="insertUser" parameterType="com.zh.demol.User">
INSERT INTO USER (username,sex,birthday,address)
VALUES (#{username},#{sex},#{birthday},#{address})
</insert>
java代码
//调用插入方法
session.insert("insertUser",new User("李四","1",new Date(),"湖北武汉"));
//增删改要提交事务
session.commit();
输出结果
28 李四 2020-02-25 1 湖北武汉
3.删除用户
<!-- 删除用户 -->
<delete id="deletUser" parameterType="int">
delete from user where id = #{id}
</delete>
java代码
//删除方法
session.delete("deletUser",26);
//增删改要提交事务
session.commit();
4.更新用户
<!-- 更新用户 -->
<update id="updateUser" parameterType="com.zh.demol.User">
update user set username=#{username},sex=#{sex} where id=#{id}
</update>
java代码
//修改方法
User user = new User();
user.setId(29);
user.setUsername("王五");
user.setSex("2");
session.update("updateUser",user);
//增删改要提交事务
session.commit();
输出结果
29 王五 2020-02-25 2 湖北武汉
5.主键返回之MySQL自增主键
<!--
[selectKey标签]:通过select查询来生成主键
[keyProperty]:指定存放生成主键的属性
[resultType]:生成主键所对应的Java类型
[order]:指定该查询主键SQL语句的执行顺序,相对于insert语句
[last_insert_id]:MySQL的函数,要配合insert语句一起使用
-->
<insert id="insertUser" parameterType="com.zh.demol.User">
<selectKey keyProperty="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO USER (username,sex,birthday,address)
VALUES(#{username},#{sex},#{birthday},#{address})
</insert>
java代码
//调用插入方法
User user = new User("李四","1",new Date(),"湖北武汉");
int afterRow = session.insert("insertUser",user);
//增删改要提交事务
session.commit();
System.out.println("收影响的行数:"+afterRow);
System.out.println("用户id:"+user.getId());
输出结果
//返回插入后的id
收影响的行数:1
用户id:31
6.主键返回之MySQL自增UUID
<insert id="insertUser" parameterType="com.gyf.domain.User">
<selectKey keyProperty="id" resultType="String" order="BEFORE">
SELECT UUID()
</selectKey>
INSERT INTO USER (username,sex,birthday,address)
VALUES(#{username},#{sex},#{birthday},#{address})
</insert>
7.MyBatis的Dao编写【mapper代理方式实现】
第一步重新写个UserMapper配置文件和定义mapper映射文件UserMapper.xml(内容同Users.xml,除了namespace的值),放到新创建的目录mapper下。
//com.zh.mapper.UserMapper
package com.zh.mapper;
import com.zh.demol.User;
public interface UserMapper {
public User findUserById(int id);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
namespace:接口全类名
id:接口方法名
parameterType:接口传入参数类型
resultType:接口返回值类型
-->
<mapper namespace="com.zh.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="com.zh.demol.User">
SELECT * FROM USER WHERE id = #{?}
</select>
</mapper>
<!-- 加在配置文件 -->
<mappers>
<mapper resource="com/zh/mapper/UserMapper.xml"></mapper>
</mappers>
java代码
public class demo02 {
@Test
public void test1() throws IOException {
//1.读取配置文件
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂。
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.获取session
SqlSession session = sessionFactory.openSession();
//4.通过session获取代理
UserMapper userMapper = session.getMapper(UserMapper.class);
User user = userMapper.findUserById(24);
System.out.println(user);
}
}
输出结果
User [id=24, username=张三丰, sex=1, birthday=null, address=河南郑州]
# Mybatis 全局配置文件
properties数据库文件配置
# src/db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8
username=root
password=root
<configuration>
<!-- 引用数据连接信息 -->
<properties resource="db.properties"></properties>
<!-- 配置mybatis的环境信息 -->
<environments default="development">
<environment id="development">
<!-- 配置JDBC事务控制,由mybatis进行管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源,采用dbcp连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<configuration>
setting【了解】
<settings>
<setting name="" value=""/>
</settings>
typeAliases(别名)
<!--src/SqlMapConfig.xml-->
<!-- 第一种方式:别名方式 -->
<typeAliases>
<typeAlias type="com.zh.demol.User" alias="u"></typeAlias>
</typeAliases>
<!--com/zh/mapper/UserMapper.xml-->
<mapper namespace="com.zh.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="u">
SELECT * FROM USER WHERE id = #{?}
</select>
</mapper>
<!--src/SqlMapConfig.xml-->
<!-- 第二种方式:包方式 -->
<typeAliases>
<package name="com.zh.demol"/>
</typeAliases>
<!--com/zh/mapper/UserMapper.xml-->
<!-- 大小写均可(User,user)-->
<mapper namespace="com.zh.mapper.UserMapper">
<select id="findUserById" parameterType="int" resultType="User">
SELECT * FROM USER WHERE id = #{?}
</select>
</mapper>
加载配置文件mappers
<!-- 加在配置文件 -->
<mappers>
<!--第一种:写映射文件的名字-->
<mapper resource="com/zh/mapper/UserMapper.xml"></mapper>
<!--第二种:写类名,一定要有映射文件UserMapper.xml-->
<mapper class="com.zh.mapper.UserMapper"></mapper>
<!--第三种:可以写包名(推荐)-->
<package name="com.zh.mapper"/>
</mappers>
# Mybatis 映射文件
# 输入映射
ParameterType
1.传递简单类型
<select id="findUserById" parameterType="int" resultType="com.zh.demol.User">
SELECT * FROM USER WHERE id = #{id}
</select>
2.传递demol对象
<!-- 更新用户 -->
<update id="updateUser" parameterType="com.zh.demol.User">
update user set username=#{username},sex=#{sex} where id=#{id}
</update>
3.传递包装对象
//1.定义包装类
package com.zh.vo;
import com.zh.demol.User;
public class UserQueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
//2.修改userMapper.java
package com.zh.mapper;
import com.zh.demol.User;
import com.zh.vo.UserQueryVo;
import java.util.List;
public interface UserMapper {
public User findUserById(int id);
//声明包装
public List<User> findUserList(UserQueryVo userQueryVo);
}
<!-- 修改UsrMappler.xml -->
<!--通过包装类查询用户-->
<select id="findUserList" parameterType="userQueryVo" resultType="user">
SELECT * FROM user WHERE sex=#{user.sex} AND username LIKE '%${user.username}%'
</select>
//测试
//构造查询对象
UserQueryVo vo = new UserQueryVo();
//设置set
User user = new User();
user.setSex("1");
user.setUsername("张");
vo.setUser(user);
//查询
List<User> users = userMapper.findUserList(vo);
System.out.println(users);
session.close();
[User [id=10, username=张三, sex=1, birthday=Thu Jul 10 00:00:00 CST 2014, address=北京市], User [id=16, username=张小明, sex=1, birthday=null, address=河南郑州], User [id=24, username=张三丰, sex=1, birthday=null, address=河南郑州], User [id=35, username=张三, sex=1, birthday=Wed Feb 26 00:00:00 CST 2020, address=湖北武汉]]
4传递Map对象
public interface UserMapper {
public List<User> findUserByMap(Map<String,Object> map);
}
<!--通过Map查询数据-->
<select id="findUserByMap" parameterType="hashmap" resultType="user">
SELECT * FROM user WHERE username = #{username} AND sex = #{sex}
</select>
Map<String,Object> map = new HashMap<String,Object>();
map.put("username","张三");
map.put("sex","1");
List<User> list = userMapper.findUserByMap(map);
System.out.println(list);
[User [id=10, username=张三, sex=1, birthday=Thu Jul 10 00:00:00 CST 2014, address=北京市], User [id=35, username=张三, sex=1, birthday=Wed Feb 26 00:00:00 CST 2020, address=湖北武汉]]
# 输出映射
resultType/resultMap
1.输出简单类型
public int findUserCount(UserQueryVo vo);
<select id="findUserCount" parameterType="userQueryVo" resultType="int">
SELECT COUNT(*) FROM user WHERE sex = #{user.sex}
</select>
//构造查询对象
UserQueryVo vo = new UserQueryVo();
//设置set
User user = new User();
user.setSex("2");
vo.setUser(user);
//查询
int count = userMapper.findUserCount(vo);
System.out.println(count);
3
2.输出POJO单个对象+列表
<select id="findUserById" parameterType="int" resultType="User">
SELECT * FROM USER WHERE id = #{?}
</select>
3.resultMap
如果查询出来的列名和属性名不一致,通过定义一个resultMap将列名和pojo属性名之间作一个映射关系。
public User findUserByIdResultMap(int id);
<!--1.设置返回数据为resultMap -->
<resultMap id="userResultMap" type="user">
<id property="id" column="id_"></id>
<result property="username" column="username_"></result>
<result property="sex" column="sex_"></result>
<result property="birthday" column="birthday_"></result>
<result property="address" column="address_"></result>
</resultMap>
<!--2.使用resultMap -->
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
SELECT id id_, username username_, sex sex_, birthday birthday_, address address_ FROM user WHERE id = #{id}
</select>
User user = userMapper.findUserByIdResultMap(1);
System.out.println(user);
User [id=1, username=王五, sex=2, birthday=null, address=null]
# Mybatis 动态SQL
# if和where
If标签:作为判断入参来使用的,如果符合条件,则把if标签体内的SQL拼接上。
注意:用if 进行判断是否为空时,不仅要判断null ,也要判断空字符串
Where标签:会去掉条件中的第一个and符号。
public List<User> findUserList(UserQueryVo userQueryVo);
<select id="findUserList" parameterType="userQueryVo" resultType="user">
SELECT * FROM user
<!-- if和where的使用 -->
<where>
<if test="user != null">
<if test="user.sex != null and user.sex != ''">
sex=#{user.sex}
</if>
<if test="user.username != null and user.username != null">
AND username LIKE '%${user.username}%'
</if>
</if>
</where>
</select>
java代码
//构造查询对象
UserQueryVo vo = new UserQueryVo();
//设置set
User user = new User();
user.setUsername("小");
vo.setUser(user);
//查询
List<User> users = userMapper.findUserList(vo);
System.out.println(users);
SELECT * FROM user WHERE username LIKE '%小%'
输出结果
[User [id=16, username=张小明, sex=1, birthday=null, address=河南郑州]]
# SQL片断
<!-- sql片段 -->
<sql id="select_user_where">
<if test="user != null">
<if test="user.sex != null and user.sex != ''">
sex=#{user.sex}
</if>
<if test="user.username != null and user.username != null">
AND username LIKE '%${user.username}%'
</if>
</if>
</sql>
<select id="findUserList" parameterType="userQueryVo" resultType="user">
SELECT * FROM user
<where>
<!-- 引用sql -->
<include refid="select_user_where"/>
</where>
</select>
# foreach 遍历
案例:查询指定id的用户 SELECT \* FROM user where id in (31,32,33);
//UserQueryVO.java
public class UserQueryVo {
private User user;
private List<Integer> ids; //get,set
}
<select id="findUserList" parameterType="userQueryVo" resultType="user">
SELECT * FROM user
<where>
<if test="ids!=null and ids.size > 0">
<!-- collection:集合,写集合属性,item:遍历接收变量,open:遍历开始,close:遍历结束
separator:拼接格式 相当于for(Integer id : ids){ }
-->
<foreach collection="ids" item="id" open="AND id IN(" close=")" separator=",">
${id}
</foreach>
</if>
</where>
</select>
java代码
//构造查询对象
UserQueryVo vo = new UserQueryVo();
//设置list
List<Integer> ids = new ArrayList<>();
ids.add(25);
ids.add(28);
ids.add(29);
vo.setIds(ids);
//查询
List<User> users = userMapper.findUserList(vo);
System.out.println(users);
SELECT * FROM user WHERE id IN( 25 , 28 , 29 )
输出结果
[User [id=25, username=陈小明, sex=1, birthday=null, address=河南郑州],
User [id=28, username=李四, sex=1, birthday=null, address=湖北武汉],
User [id=29, username=王五, sex=2, birthday=null, address=湖北武汉]]
# Mybatis 多表查询
# 一对一
# resultType实现
复杂查询时,单表对应的po类已不能满足输出结果集的映射。所以要根据需求建立一个扩展类来作为resultType的类型。
public class Orders {
//提供get,set方法,toString
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
}
第一步:写个定单的扩展类
public class OrdersExt extends Orders{
//提供get,set,toString和父类方法
private String username;
private String address;
public String toString() {
return "OrdersExt{" +
"username='" + username + '\'' +
", address='" + address + '\'' +
'}'+super.toString();
}
}
第二步:声明定单接口
package com.zh.mapper;
import com.zh.demol.OrdersExt;
public interface OrderMapper {
//根据id信息查询,返回扩展类对象
public OrdersExt findOrderById(int id);
}
第三步:声明定单配置文件
<mapper namespace="com.zh.mapper.OrderMapper">
<select id="findOrderById" parameterType="int" resultType="OrdersExt">
SELECT o.*,u.username,u.address
FROM orders o,user u
WHERE o.user_id = u.id AND o.id = #{id}
</select>
</mapper>
第四步:加载映射文件
<mapper resource="com/zh/mapper/OrderMapper.xml"></mapper>
第五步:测试
//1.通过session获取代理
OrderMapper orderMapper = session.getMapper(OrderMapper.class);
//2.ordersExt
OrdersExt ordersExt = orderMapper.findOrderById(5);
System.out.println(ordersExt);
session.close();
输出
OrdersExt{username='张三', address='北京市'}Orders{id=5, userId=null, number='1000012', createtime=Thu Feb 12 16:13:23 CST 2015, note='null'}
# resultMap实现
第一步:在orders里添加一个user对象
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
第二步:声明定单接口
package com.zh.mapper;
import com.zh.demol.OrdersExt;
public interface OrderMapper {
//根据id信息查询,返回扩展类对象
public Orders findOrdersByResultMap(int ordersId);
}
第三步:声明定单配置文件
<resultMap id="ordersRslMap" type="orders">
<result column="id" property="id"></result>
<result column="number" property="number"></result>
<result column="createtime" property="createtime"></result>
<result column="note" property="note"></result>
<!--关联内部对象-->
<association property="user" javaType="com.zh.demol.User">
<result column="username" property="username"></result>
<result column="address" property="address"></result>
</association>
</resultMap>
<select id="findOrdersByResultMap" parameterType="int" resultMap="ordersRslMap">
SELECT o.*,u.username,u.address
FROM orders o,user u
WHERE o.user_id = u.id AND o.id = #{id}
</select>
第四步:加载映射文件
<mapper resource="com/zh/mapper/OrderMapper.xml"></mapper>
第五步:测试
//1.通过session获取代理
OrderMapper orderMapper = session.getMapper(OrderMapper.class);
//2.ordersExt
Orders orders = orderMapper.findOrdersByResultMap(5);
System.out.println(orders);
System.out.println(orders.getUser());
# 一对多
根据定单ID查找定单信息、用户信息和定单明细信息
//订单明细模型
package com.zh.demol;
public class OrderDetail {
private Integer id;//定单详情ID
private Integer itemsId;//商品ID
private Integer itemsNum;//商品购买数量
}
第一步:在Orders中添加定单明细
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//用户信息
private User user;
//订单明细
private List<OrderDetail> orderDetails;
}
第二步:Mapper接口
public interface OrderMapper {
//一对多查询
public Orders findOrdersByRsltMap(int ordersId);
}
第三步:OrderMapper.xml
<resultMap id="ordersRslMap" type="orders">
<!--匹配orders-->
<result column="id" property="id"></result>
<result column="number" property="number"></result>
<result column="createtime" property="createtime"></result>
<result column="note" property="note"></result>
<!--匹配orders里的user 一对一-->
<association property="user" javaType="com.zh.demol.User">
<id column="user_id" property="id"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
</association>
<!--匹配orders里的orderdetail 一对多
注意:集合里类型使用ofType,而不javaType
property: orders里的private List<OrderDetail> orderDetails;
-->
<collection property="orderDetails" ofType="OrderDetail">
<id column="detail_id" property="id"></id>
<result column="items_id" property="itemsId"></result>
<result column="items_num" property="itemsNum"></result>
</collection>
</resultMap>
<select id="findOrdersByRsltMap" parameterType="int" resultMap="ordersRslMap">
Select
orders.id,orders.user_id,orders.number,
orders.createtime,orders.note,
user.username,user.address,
orderdetail.id detail_id,orderdetail.items_id,orderdetail.items_num
from
orders,user,orderdetail
where
orders.user_id = user.id
and orders.id = orderdetail.orders_id
and orders.id = #{?};
</select>
第四步:测试
//1.通过session获取代理
OrderMapper orderMapper = session.getMapper(OrderMapper.class);
//2.ordersExt
Orders orders = orderMapper.findOrdersByRsltMap(3);
System.out.println(orders);
System.out.println(orders.getUser());
for(OrderDetail orderDetail:orders.getOrderDetails()){
System.out.println(orderDetail);
}
Orders{id=3, userId=null, number='1000010', createtime=Wed Feb 04 13:22:35 CST 2015, note='null'}
User [id=1, username=王五, sex=null, birthday=null, address=null]
OrderDetail{id=1, itemsId=1, itemsNum=1}
OrderDetail{id=2, itemsId=2, itemsNum=3}
# 多对多
映射思路
⭐ 将用户信息映射到user中。
⭐ 在user类中添加订单列表属性List<Orders> orderslist
,将用户创建的订单映射到orderslist
⭐ 在Orders中添加订单明细列表属性List<Orderdetail> detailList
,将订单的明细映射到detailList
⭐ 在Orderdetail中添加Items属性,将订单明细所对应的商品映射到Items第一步:UserMapper.java
public interface UserMapper {
//查找用户购买的商品信息
public List<User> findUserAndOrderInfo();
}
第二步:User/Orders/Orderdetail.java
//user模型:一个用户有多个订单
public class User implements Serializable {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
private List<Orders> orderList; //一个用户有多个订单
}
//orders模型:一个订单有多张明细
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//订单明细
private List<OrderDetail> orderDetails;
}
//OrderDetail:详情对应的商品
public class OrderDetail {
private Integer id;//定单详情ID
private Integer itemsId;//商品ID
private Integer itemsNum;//商品购买数量
private Items items; //订单详情对应的商品
}
//商品购买信息
package com.zh.demol;
public class Items {
private Integer id;
private String name;
private String price;
private String detail;
}
第三步:UserMapper.xml
<resultMap id="userRslMap" type="user">
<id column="id" property="id"></id>
<result column="address" property="address"></result>
<!-- 2.匹配user的orderList -->
<collection property="orderList" ofType="orders">
<id column="order_id" property="id"></id>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 3.匹配Orders里有orderDetails-->
<collection property="orderDetails" ofType="orderDetail">
<id column="detail_id" property="id"></id>
<result column="items_id" property="itemsId"></result>
<result column="items_num" property="itemsNum"></result>
<!-- 4.配置定单详情的商品信息-->
<association property="items" javaType="items">
<id column="name" property="name"></id>
<result column="price" property="price"></result>
<result column="detail" property="detail"></result>
</association>
</collection>
</collection>
</resultMap>
<select id="findUserAndOrderInfo" resultMap="userRslMap">
SELECT u.id,u.username,u.address,
o.id order_id,o.number,o.createtime,o.note,
od.id detail_id,od.items_id,od.items_num,
it.name,it.price,it.detail
FROM
user u,orders o,orderdetail od,items it
WHERE
o.user_id = u.id
AND o.id = od.orders_id
AND od.items_id = it.id;
</select>
第四步:测试
//1.通过session获取代理
UserMapper userMapper = session.getMapper(UserMapper.class);
//2.获取user集合
List<User> users = userMapper.findUserAndOrderInfo();
for (User user:users){
System.out.println("用户信息:"+user);
for(Orders order:user.getOrderList()){
System.out.println("订单信息:"+order);
System.out.println("订单详情");
for(OrderDetail orderDetail:order.getOrderDetails()){
System.out.println(orderDetail+":"+orderDetail.getItems());
}
}
}
用户信息:User [id=1, username=null, sex=null, birthday=null, address=null]
订单信息:Orders{id=3, userId=null, number='1000010', createtime=Wed Feb 04 13:22:35 CST 2015, note='null'}
订单详情
OrderDetail{id=1, itemsId=1, itemsNum=1}:com.zh.demol.Items@2504df84
OrderDetail{id=2, itemsId=2, itemsNum=3}:com.zh.demol.Items@62ee6618
订单信息:Orders{id=4, userId=null, number='1000011', createtime=Tue Feb 03 13:22:41 CST 2015, note='null'}
订单详情
OrderDetail{id=3, itemsId=3, itemsNum=4}:com.zh.demol.Items@1170e466
OrderDetail{id=4, itemsId=2, itemsNum=3}:com.zh.demol.Items@aa2ed7c
# 一级缓存
测试1
//使用一级缓存
UserMapper userMapper = session.getMapper(UserMapper.class);
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//第二次不会执行sql
User user2 = userMapper.findUserById(1);
System.out.println(user2);
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id = ?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
User [id=1, username=王五, sex=2, birthday=null, address=null]
User [id=1, username=王五, sex=2, birthday=null, address=null]
测试2
//一级缓存
UserMapper userMapper = session.getMapper(UserMapper.class);
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//保存,删除,更新后会清除一级缓存
User user = new User("张三", "1", new Date(), "湖北武汉");
userMapper.save(user);
//第二次将执行sql
User user2 = userMapper.findUserById(1);
System.out.println(user2);
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id = ? --第一次执行sql
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
User [id=1, username=王五, sex=2, birthday=null, address=null]
DEBUG [main] - ==> Preparing: INSERT INTO USER (username,sex,birthday,address) VALUES(?,?,?,?) --清除了缓存
DEBUG [main] - ==> Parameters: 张三(String), 1(String), 2020-02-28 12:15:32.777(Timestamp), 湖北武汉(String)
DEBUG [main] - <== Updates: 1
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id = ? --第二次执行sql
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
User [id=1, username=王五, sex=2, birthday=null, address=null]
# 二级缓存
1.开启二级缓存总开关
<settings>
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
<!--配置懒加载-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
2.UserMapper中配置二级缓存
<mapper namespace="com.zh.mapper.UserMapper">
<cache></cache>
</mapper>
3.User系列化
//实现Serializable序列化
public class User implements Serializable{
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
}
4.测试1
//获取session
SqlSession session1 = sessionFactory.openSession();
SqlSession session2 = sessionFactory.openSession();
//获取mapper
UserMapper userMapper1 = session1.getMapper(UserMapper.class);
UserMapper userMapper2 = session2.getMapper(UserMapper.class);
//二级缓存
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//session关闭会写入二级缓存
session1.close();
//第二次不会执行sql
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
session2.close();
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id = ? --第一次执行sql
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
User [id=1, username=王五, sex=2, birthday=null, address=null]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@48f87a17]
DEBUG [main] - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@48f87a17]
DEBUG [main] - Returned connection 1224243735 to pool.
DEBUG [main] - Cache Hit Ratio [com.zh.mapper.UserMapper]: 0.5 --从二级缓存中取
User [id=1, username=王五, sex=2, birthday=null, address=null]
4.测试2
//获取session
SqlSession session1 = sessionFactory.openSession();
SqlSession session2 = sessionFactory.openSession();
SqlSession session3 = sessionFactory.openSession();
//获取mapper
UserMapper userMapper1 = session1.getMapper(UserMapper.class);
UserMapper userMapper2 = session2.getMapper(UserMapper.class);
UserMapper userMapper3 = session3.getMapper(UserMapper.class);
//二级缓存
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//session关闭会写入二级缓存
session1.close();
//保存,删除,更新后会清除二级缓存
userMapper3.save(user1);
session3.commit();
//第二次将执行sql
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id = ?
User [id=1, username=王五, sex=2, birthday=null, address=null]
DEBUG [main] - ==> Preparing: INSERT INTO USER (username,sex,birthday,address) VALUES(?,?,?,?) --二级缓存被清除
DEBUG [main] - ==> Parameters: 王五(String), 2(String), null, null
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id = ? --第二次执行sql
User [id=1, username=王五, sex=2, birthday=null, address=null]
禁用指定方法二级缓存
<select id="findUserById" parameterType="int" resultType="User" useCache="false">
SELECT * FROM USER WHERE id = #{?}
</select>
刷新缓存
<!-- 刷新二级缓存,设置为false保存,删除,更新后不会清除二级缓存-->
<insert id="save" parameterType="user" flushCache="false">
INSERT INTO USER (username,sex,birthday,address)
VALUES(#{username},#{sex},#{birthday},#{address})
</insert>
# 整合ehcache
整合思路Cache是一个接口,它的默认实现是mybatis的PerpetualCache。如果想整合mybatis的二级缓存,那么实现Cache接口即可。
1.添加jar包
ehcache-core-2.6.5.jar
mybatis-ehcache-1.0.2.jar
2.设置映射文件中cache标签
<mapper namespace="com.zh.mapper.UserMapper">
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"></cache>
</mapper>
3.在src下添加ehcache的配置文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
</ehcache>
测试:用上面二级缓存例子即可
# 逆向工程
1.创建generator.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="mysqlTables" targetRuntime="MyBatis3">
<!--数据库配置-->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root"
password="root">
</jdbcConnection>
<!-- java类型解析 -->
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- 模型生成包名-->
<javaModelGenerator targetPackage="com.zh.backoffice.model" targetProject=".\src">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- mybatis的映射.xml-->
<sqlMapGenerator targetPackage="com.zh.backoffice.mapper" targetProject=".\src">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- mybatis 的mapper接口生成的包路径-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.zh.backoffice.mapper" targetProject=".\src">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<!-- 配置生成表的模型-->
<table tableName="item" domainObjectName="Item" ></table>
<table tableName="orderdetail" domainObjectName="OrderDetail" ></table>
<table tableName="orders" domainObjectName="Orders" ></table>
<table tableName="user" domainObjectName="User" ></table>
</context>
</generatorConfiguration>
2.使用java类来执行逆向工程
需要导入mysql的驱动包和mybatis的逆向工程包
public class Main {
public static void main(String[] args) throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("src/generator.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
callback, warnings);
myBatisGenerator.generate(null);
}
}