Mybatis动态SQL
1.if标签
IUserDao接口
/**
*
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 根据条件查询用户
*/
List<User> findUserByCondition(User user);
}
IUserDao.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">
<mapper namespace="com.ginger.dao.IUserDao">
<select id="findUserByCondition" parameterType="com.ginger.pojo.User" resultType="com.ginger.pojo.User">
select * from user where 1 = 1
<if test="username!=null">
and username like #{username}
</if>
<if test="sex!=null">
and sex like #{sex}
</if>
</select>
</mapper>
测试
public class MybatisTest {
private InputStream in;
private IUserDao userDao;
@Before//用于在测试方法执行之前执行
public void init() throws Exception {
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.使用工厂对象获取session对象
SqlSession session = factory.openSession();
//4.使用工厂对象,创建dao对象
userDao = session.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy() throws Exception {
//6.释放资源
in.close();
}
@Test
public void test(){
/*
一个参数执行拼接sql
select * from user where 1 = 1 and username like ?
两个参数执行拼接sql
select * from user where 1 = 1 and username like ? and sex like ?
*/
User u = new User();
u.setUsername("%诡术%");
u.setSex("男");
List<User> users = userDao.findUserByCondition(u);
for (User user : users) {
System.out.println(user);
}
}
}
结果:
User{id=42, username='诡术妖姬', address='巨龙之巢', sex='男', birthday=Fri Mar 02 15:09:37 CST 2018}
2.where标签
IUserDao接口
/**
*
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 根据条件查询用户
*/
List<User> findUserByCondition(User user);
}
IUserDao.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">
<mapper namespace="com.ginger.dao.IUserDao">
<select id="findUserByCondition" parameterType="com.ginger.pojo.User" resultType="com.ginger.pojo.User">
<!--select * from user where 1 = 1-->
select * from user
<!--使用where标签代替 where 1 = 1-->
<where>
<if test="username!=null">
and username like #{username}
</if>
<if test="sex!=null">
and sex like #{sex}
</if>
</where>
</select>
</mapper>
测试
public class MybatisTest {
private InputStream in;
private IUserDao userDao;
@Before//用于在测试方法执行之前执行
public void init() throws Exception {
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.使用工厂对象获取session对象
SqlSession session = factory.openSession();
//4.使用工厂对象,创建dao对象
userDao = session.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy() throws Exception {
//6.释放资源
in.close();
}
@Test
public void test(){
/*
使用where标签拼接sql
select * from user WHERE username like ? and sex like ?
*/
User u = new User();
u.setUsername("%诡术%");
u.setSex("男");
List<User> users = userDao.findUserByCondition(u);
for (User user : users) {
System.out.println(user);
}
}
}
结果:
User{id=42, username='诡术妖姬', address='巨龙之巢', sex='男', birthday=Fri Mar 02 15:09:37 CST 2018}
3.foreach标签以及include标签
IUserDao接口
/**
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 根据vo查询用户
* @param vo
* @return
*/
List<User> findUserByQueryVo(QueryVo vo);
}
IUserDao.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">
<mapper namespace="com.ginger.dao.IUserDao">
<!--抽取重复的sql语句-->
<sql id="defaultUser">
select * from user
</sql>
<select id="findUserByQueryVo" parameterType="com.ginger.pojo.QueryVo" resultType="com.ginger.pojo.User">
<include refid="defaultUser"></include>
<where>
<if test="ids!=null and ids.size()>0">
<foreach collection="ids" open=" and id in (" close=")" item="id" separator=",">
#{id}
</foreach>
</if>
</where>
</select>
</mapper>
测试
public class MybatisTest {
private InputStream in;
private IUserDao userDao;
@Before//用于在测试方法执行之前执行
public void init() throws Exception {
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.使用工厂对象获取session对象
SqlSession session = factory.openSession();
//4.使用工厂对象,创建dao对象
userDao = session.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy() throws Exception {
//6.释放资源
in.close();
}
@Test
public void test2(){
ArrayList<Integer> lists = new ArrayList<Integer>();
lists.add(41);
lists.add(42);
lists.add(43);
QueryVo vo = new QueryVo();
vo.setIds(lists);
List<User> users = userDao.findUserByQueryVo(vo);
for (User user : users) {
System.out.println(user);
}
}
}
结果
User{id=41, username='男枪', address='征服之海', sex='男', birthday=Wed Jun 10 11:25:58 CST 2020}
User{id=42, username='诡术妖姬', address='巨龙之巢', sex='男', birthday=Fri Mar 02 15:09:37 CST 2018}
User{id=43, username='诡术妖姬', address='征服之海', sex='女', birthday=Sun Mar 04 11:34:34 CST 2018}
Mybatis中多表操作
表之间的关系有几种:
一对多
多对一
一对一
多对多
举例:
用户和订单就是一对多
订单和用户就是多对一
一个用户可以下多个订单
多个订单属于同一个用户
人和身份证号就是一对一
一个人只能有一个身份证号
一个身份证号只能属于一个人
老师和学生之间就是多对多
一个学生可以被多个老师教过
一个老师可以交多个学生
特例:
如果拿出每一个订单,他都只能属于一个用户。
所以Mybatis就把多对一看成了一对一。
1.一对一
账户对用户是一对一
1.IAccountDao接口
/**
* 账户持久层接口
*/
public interface IAccountDao {
/**
* 查询账户
* @return
*/
List<Account> findAll();
}
2.Account实体类
public class Account {
private Integer id;
private Integer uid;
private Double money;
//对用户是一对一
private User user;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
", user=" + user +
'}';
}
}
3.IAccountMapper.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">
<mapper namespace="com.ginger.dao.IAccountDao">
<resultMap id="defaultAccount" type="account">
<!--id:声明主键,表示id是关联查询对象的唯一标识-->
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--association:配置一对一属性 -->
<!--property:account里面的user属性名 -->
<!--javaType:java属性类型 -->
<!--column:对应着account里面的uid一对一属性,可以选择不写也没事。-->
<association property="user" column="uid" javaType="user">
<!--id:声明主键,表示id是关联查询对象的唯一标识。-->
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</association>
</resultMap>
<!--一对一关联-->
<select id="findAll" resultMap="defaultAccount">
SELECT
u.*,
a.id AS aid,
a.uid,
a.money
FROM
account a,
USER u
WHERE a.uid = u.id
</select>
</mapper>
4.IAccountDaoTest测试
public class IAccountDaoTest {
private InputStream in;
private IAccountDao accountDao;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//使用工厂对象创建SqlSession对象
SqlSession session = factory.openSession();
//使用SqlSession对象创建dao代理对象
accountDao = session.getMapper(IAccountDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
//释放资源
in.close();
}
/**
* 查询一对一
*/
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
for (Account account : accounts) {
System.out.println(account);
}
}
}
结果:
Account{id=1, uid=46, money=1000.0, user=User{id=46, username='格雷福斯', address='班德尔城', sex='男', birthday=Wed Mar 07 17:37:26 CST 2018}}
Account{id=2, uid=45, money=1000.0, user=User{id=45, username='影流之主', address='影流', sex='男', birthday=Sun Mar 04 12:04:06 CST 2018}}
Account{id=3, uid=46, money=2000.0, user=User{id=46, username='格雷福斯', address='班德尔城', sex='男', birthday=Wed Mar 07 17:37:26 CST 2018}}
2.一对多
用户对账户是一对多
1.IUserDao接口
/**
*
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
List<User> findAll();
}
2.User实体类
/**
* 用户实体类
*/
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//对账户一对多
private List<Account> accounts;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}'+accounts;
}
}
3.IUserMapper.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">
<mapper namespace="com.ginger.dao.IUserDao">
<resultMap id="userDefault" type="user">
<!--配置主键-->
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<collection property="accounts" ofType="account">
<!--配置主键-->
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
</collection>
</resultMap>
<!-- 查询所有-->
<select id="findAll" resultMap="userDefault">
SELECT
u.*,
a.id AS aid,
a.uid,
a.money
FROM
USER u
LEFT JOIN account a
ON u.id = a.uid
</select>
</mapper>
4.IUserDaoTest测试类
public class IUserDaoTest {
private InputStream in;
private IUserDao userDao;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//使用工厂对象创建SqlSession对象
SqlSession session = factory.openSession();
//使用SqlSession对象创建dao代理对象
userDao = session.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
//释放资源
in.close();
}
/**
* 查询所有用户
*/
@Test
public void testFindAll(){
//执行查询所有方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
}
}
结果:
User{id=41, username='男枪', address='征服之海', sex='男', birthday=Wed Jun 10 11:25:58 CST 2020}[]
User{id=42, username='诡术妖姬', address='巨龙之巢', sex='男', birthday=Fri Mar 02 15:09:37 CST 2018}[]
User{id=43, username='诡术妖姬', address='征服之海', sex='女', birthday=Sun Mar 04 11:34:34 CST 2018}[]
User{id=45, username='影流之主', address='影流', sex='男', birthday=Sun Mar 04 12:04:06 CST 2018}[Account{id=2, uid=45, money=1000.0, user=null}]
User{id=46, username='格雷福斯', address='班德尔城', sex='男', birthday=Wed Mar 07 17:37:26 CST 2018}[Account{id=1, uid=46, money=1000.0, user=null}, Account{id=3, uid=46, money=2000.0, user=null}]
User{id=48, username='光辉女郎', address='德玛西亚', sex='女', birthday=Thu Mar 08 11:44:00 CST 2018}[]
User{id=51, username='疾风剑豪', address='艾欧尼亚', sex='男', birthday=Wed Jun 10 11:25:58 CST 2020}[]
3.多对多
1.一个角色对用户(一对多)
1.IRoleDao接口
/**
*
* 角色持久层接口
*/
public interface IRoleDao {
/**
* 查询角色
* @return
*/
List<Role> findAll();
}
2.Role实体类
public class Role {
private Integer id;
private String rolename;
private String roledesc;
//一个角色对用户一对多
private List<User> users;
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRolename() {
return rolename;
}
public void setRolename(String rolename) {
this.rolename = rolename;
}
public String getRoledesc() {
return roledesc;
}
public void setRoledesc(String roledesc) {
this.roledesc = roledesc;
}
@Override
public String toString() {
return "Role{" +
"id=" + id +
", rolename='" + rolename + '\'' +
", roledesc='" + roledesc + '\'' +
'}' + users;
}
}
3.IRoleMapper.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">
<mapper namespace="com.ginger.dao.IRoleDao">
<resultMap id="roleDefault" type="role">
<id property="id" column="rid"></id>
<result property="rolename" column="role_name"></result>
<result property="roledesc" column="role_desc"></result>
<collection property="users" ofType="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
</collection>
</resultMap>
<select id="findAll" resultMap="roleDefault">
SELECT
r.id AS rid,
r.role_name,
r.role_desc,
u.*
FROM
role r
LEFT JOIN user_role ur
ON r.id = ur.rid
LEFT JOIN USER u
ON ur.uid = u.id
</select>
</mapper>
4.IRoleDaoTest测试类
public class IRoleDaoTest {
private InputStream in;
private IRoleDao roleDao;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//使用工厂对象创建SqlSession对象
SqlSession session = factory.openSession();
//使用SqlSession对象创建dao代理对象
roleDao = session.getMapper(IRoleDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
//释放资源
in.close();
}
/**
* 查询多对多
*/
@Test
public void testFindAll(){
List<Role> roles = roleDao.findAll();
for (Role role : roles) {
System.out.println(role);
}
}
}
结果:
Role{id=1, rolename='院长', roledesc='管理整个学院'}[User{id=41, username='男枪', address='征服之海', sex='男', birthday=Wed Jun 10 11:25:58 CST 2020}null, User{id=45, username='影流之主', address='影流', sex='男', birthday=Sun Mar 04 12:04:06 CST 2018}]
Role{id=2, rolename='总裁', roledesc='管理整个公司'}[User{id=41, username='男枪', address='征服之海', sex='男', birthday=Wed Jun 10 11:25:58 CST 2020}]
Role{id=3, rolename='校长', roledesc='管理整个学校'}[]
2.一个用户对角色(一对多)
1.IUserDao接口
/**
*
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
List<User> findAll();
}
2.User实体类
/**
* 用户实体类
*/
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//一个用户对角色一对多
List<Role> roles ;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}'+roles;
}
}
3.IUserMapper.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">
<mapper namespace="com.ginger.dao.IUserDao">
<resultMap id="userDefault" type="user">
<!--配置主键-->
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<collection property="roles" ofType="role">
<!--配置主键-->
<id property="id" column="rid"></id>
<id property="rolename" column="role_name"></id>
<id property="roledesc" column="role_desc"></id>
</collection>
</resultMap>
<!-- 查询所有-->
<select id="findAll" resultMap="userDefault">
SELECT
u.*,
r.id AS rid,
r.role_name,
r.role_desc
FROM
USER u
LEFT JOIN user_role ur
ON u.id = ur.uid
LEFT JOIN role r
ON ur.rid = r.id
</select>
</mapper>
4.IUserDaoTest测试类
/**
* 测试类
*/
public class IUserDaoTest {
private InputStream in;
private IUserDao userDao;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//使用工厂对象创建SqlSession对象
SqlSession session = factory.openSession();
//使用SqlSession对象创建dao代理对象
userDao = session.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
//释放资源
in.close();
}
/**
* 查询所有用户
*/
@Test
public void testFindAll(){
//执行查询所有方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
}
}
结果:
User{id=41, username='男枪', address='征服之海', sex='男', birthday=Wed Jun 10 11:25:58 CST 2020}[Role{id=1, rolename='院长', roledesc='管理整个学院'}Role{id=2, rolename='总裁', roledesc='管理整个公司'}]
User{id=42, username='诡术妖姬', address='巨龙之巢', sex='男', birthday=Fri Mar 02 15:09:37 CST 2018}[]
User{id=43, username='诡术妖姬', address='征服之海', sex='女', birthday=Sun Mar 04 11:34:34 CST 2018}[]
User{id=45, username='影流之主', address='影流', sex='男', birthday=Sun Mar 04 12:04:06 CST 2018}[Role{id=1, rolename='院长', roledesc='管理整个学院'}]
User{id=46, username='格雷福斯', address='班德尔城', sex='男', birthday=Wed Mar 07 17:37:26 CST 2018}[]
User{id=48, username='光辉女郎', address='德玛西亚', sex='女', birthday=Thu Mar 08 11:44:00 CST 2018}[]
User{id=51, username='疾风剑豪', address='艾欧尼亚', sex='男', birthday=Wed Jun 10 11:25:58 CST 2020}[]
Mybatis中的延迟加载
在查询用户的时候,要不要把关联的账户查出来?
在查询账户的时候,要不要把关联的用户查出来?
在查询用户时,用户下的账户信息应该是,什么时候使用,什么时候查询的。
在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询出来。
什么是延迟加载
在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)
什么是立即加载
不管用不用,只要一调用方法,马上发起查询。
在对应的四种表关系中:一对多,多对一,一对一,多对多
一对多,多对多:通常情况下我们都是采用延迟加载。
多对一,一对一:通常情况下我们都是采用立即加载。
延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。
好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
1.使用assocation实现延迟加载(一对一)
要想实现延迟加载,下面的以前的sql语句可定不可以,因为一执行就会把所有的数据都查询出来,只有分成两个sql才能实现延迟加载。
<!--一对一关联-->
<select id="findAll" resultMap="accountDefault">
select u.*,a.id as aid,a.uid,a.money from account a , user u where a.uid = u.id
</select>
1.接口
/**
* 账户的持久层接口
*/
public interface IAccountDao {
/**
* 查询账户
* @return
*/
List<Account> findAll();
}
/**
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
List<User> findAll();
/**
* 根据id查询用户
* @return
*/
User findUserById();
}
2.实体类
/**
* 账户实体类
*/
public class Account {
private Integer id;
private Integer uid;
private Double money;
//对用户是一对一
private User user;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
", user=" + user +
'}';
}
}
/**
* 用户实体类
*/
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//对账户一对多
List<Account> accounts;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}';
}
}
3.映射文件
IAccountMapper.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">
<mapper namespace="com.ginger.dao.IAccountDao">
<resultMap id="accountDefault" type="account">
<!--id:声明主键,表示id是关联查询对象的唯一标识-->
<id property="id" column="aid"></id>
<result property="uid" column="uid"></result>
<result property="money" column="money"></result>
<!--association配置延时加载
配置一对一映射
select:通过方法全限定名定位到sql语句。
select * from user where id = #{id}
column:就是查询语句中的id,这个id是account表中的uid。
-->
<association property="user" column="uid" javaType="user" select="com.ginger.dao.IUserDao.findUserById">
</association>
</resultMap>
<!--一对一关联-->
<select id="findAll" resultMap="accountDefault">
select * from account
</select>
</mapper>
IUserMapper.xml
<select id="findUserById" parameterType="int" resultType="user">
select * from user where id = #{id}
</select>
4.配置文件
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>
<!--开启延迟加载-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!--配置别名-->
<typeAliases>
<package name="com.ginger.pojo"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务 -->
<transactionManager type="JDBC"></transactionManager>
<!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///mybatis"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件的位置 -->
<mappers>
<mapper resource="com/ginger/dao/IAccountMapper.xml"></mapper>
<mapper resource="com/ginger/dao/IUserMapper.xml"></mapper>
</mappers>
</configuration>
5.测试
public class IAccountDaoTest {
private InputStream in;
private IAccountDao accountDao;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//使用工厂对象创建SqlSession对象
SqlSession session = factory.openSession();
//使用SqlSession对象创建dao代理对象
accountDao = session.getMapper(IAccountDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
//释放资源
in.close();
}
/**
* 查询一对一
*/
@Test
public void testFindAll(){
List<Account> accounts = accountDao.findAll();
/*for (Account account : accounts) {
System.out.println(account);
}*/
}
}
6.一对一延时加载分析
没有开启延时加载,会把sql一次性执行完,开启延时加载,需要时在执行sql。
2.使用Collection实现延迟加载(一对多)
1.接口
/**
*
* 账户的持久层接口
*/
public interface IAccountDao {
/**
* 查询账户
* @return
*/
List<Account> findAll();
/**
* 根据id查询账户
* @return
*/
Account findAccountById();
}
/**
*
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
List<User> findAll();
/**
* 根据id查询用户
* @return
*/
User findUserById();
}
2.实体类
/**
* 账户实体类
*/
public class Account {
private Integer id;
private Integer uid;
private Double money;
//对用户是一对一
private User user;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", uid=" + uid +
", money=" + money +
'}';
}
}
/**
* 用户实体类
*/
public class User implements Serializable {
private Integer id;
private String username;
private String address;
private String sex;
private Date birthday;
//对账户一对多
List<Account> accounts;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
", birthday=" + birthday +
'}'+accounts;
}
}
3.映射文件
IUserMapper.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">
<mapper namespace="com.ginger.dao.IUserDao">
<resultMap id="userDefault" type="user">
<!--配置主键-->
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="address" column="address"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<!--collection配置延时加载
配置一对多映射
select:通过方法全限定名定位到sql语句。
select * from account where uid = #{uid}
column:就是查询语句中的id,这个id是user表中的id。
-->
<collection property="accounts" ofType="account" column="id" select="com.ginger.dao.IAccountDao.findAccountById" ></collection>
</resultMap>
<!--查询一对多-->
<select id="findAll" resultMap="userDefault">
select * from user
</select>
</mapper>
IAccountMapper.xml
<!--根据uid查询账户-->
<select id="findAccountById" resultType="account">
select * from account where uid = #{uid}
</select>
4.配置文件
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>
<!--开启延迟加载-->
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!--配置别名-->
<typeAliases>
<package name="com.ginger.pojo"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务 -->
<transactionManager type="JDBC"></transactionManager>
<!--配置连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///mybatis"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</dataSource>
</environment>
</environments>
<!-- 配置映射文件的位置 -->
<mappers>
<mapper resource="com/ginger/dao/IAccountMapper.xml"></mapper>
<mapper resource="com/ginger/dao/IUserMapper.xml"></mapper>
</mappers>
</configuration>
5.测试
public class IUserDaoTest {
private InputStream in;
private IUserDao userDao;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//使用工厂对象创建SqlSession对象
SqlSession session = factory.openSession();
//使用SqlSession对象创建dao代理对象
userDao = session.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
//释放资源
in.close();
}
/**
* 查询一对多
*/
@Test
public void testFindAll(){
List<User> users = userDao.findAll();
/*for (User user : users) {
System.out.println(user);
}*/
}
}
6.一对多延时加载分析
Mybatis缓存
Mybatis中缓存分为一级缓存,二级缓存。
Mybatis中的缓存
什么是缓存
存在于内存中的临时数据。
为什么使用缓存
减少和数据库的交互次数,提高执行效率。
什么样的数据能使用缓存,什么样的数据不能使用
适用于缓存:
经常查询并且不经常改变的。
数据的正确与否对最终结果影响不大的。
不适用于缓存:
经常改变的数据
数据的正确与否对最终结果影响很大的。
例如:商品的库存,银行的汇率,股市的牌价。
Mybatis中的一级缓存和二级缓存
一级缓存:
它指的是Mybatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中
查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。
二级缓存:
它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
二级缓存的使用步骤:
第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
第三步:让当前的操作支持二级缓存(在select标签中配置)
1.Mybatis 一级缓存
Mybatis 中缓存分为一级缓存,二级缓存。
1.接口
/**
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有用户,同时获取到用户下所有账户的信息
* @return
*/
List<User> findAll();
/**
* 根据id查询用户信息
* @param userId
* @return
*/
User findById(Integer userId);
/**
* 更新用户信息
* @param user
*/
void updateUser(User user);
}
2.IUserDao.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">
<mapper namespace="com.ginger.dao.IUserDao">
<!-- 查询所有 -->
<select id="findAll" resultType="user">
select * from user
</select>
<!-- 根据id查询用户 -->
<select id="findById" parameterType="int" resultType="user">
select * from user where id = #{uid}
</select>
<!-- 更新用户信息-->
<update id="updateUser" parameterType="user">
update user set username=#{username},address=#{address} where id=#{id}
</update>
</mapper>
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-->
<properties resource="jdbcConfig.properties"></properties>
<!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
<typeAliases>
<package name="com.ginger.pojo"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置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>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.ginger.dao"></package>
</mappers>
</configuration>
4.一级缓存测试
public class FirstLevelCache {
InputStream inputStream;
SqlSessionFactory sqlSessionFactory;
SqlSession sqlSession;
IUserDao userdao;
@Before//用于在测试方法执行之前执行
public void init() throws Exception {
//1.读取配置文件,生成字节输入流
inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.获取SqlSession对象
sqlSession = sqlSessionFactory.openSession();
//4.获取代理对象
userdao = sqlSession.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy() throws Exception {
//提交事务
sqlSession.commit();
//关闭资源
inputStream.close();
sqlSession.close();
}
/**
* 测试一级缓存
*/
@Test
public void test() {
//查询相同的数据,测试缓存。
User user1 = userdao.findById(41);
User user2 = userdao.findById(41);
System.out.println(user1 == user2);
}
/**
* 测试一级缓存
* 使用多个SqlSession多个对象测试,执行sql。
*/
@Test
public void test2() {
//查询相同的数据,测试缓存。
User user1 = userdao.findById(41);
//关闭SqlSession
sqlSession.close();
//重新获取SqlSession
sqlSession = sqlSessionFactory.openSession();
//重新获取代理对象
userdao = sqlSession.getMapper(IUserDao.class);
User user2 = userdao.findById(41);
System.out.println(user1 == user2);
}
/**
* 测试一级缓存
* 清空SqlSession缓存
*/
@Test
public void test3() {
//查询相同的数据,测试缓存。
User user1 = userdao.findById(41);
//清除SqlSession缓存
sqlSession.clearCache();
userdao = sqlSession.getMapper(IUserDao.class);
User user2 = userdao.findById(41);
System.out.println(user1 == user2);
}
/**
* 测试缓存同步
*/
@Test
public void test4(){
//查询
User user1 = userdao.findById(41);
//更新
User user = new User();
user.setId(51);
user.setUsername("亚索");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("雷瑟守备");
userdao.updateUser(user);
//再次查询
User user2 = userdao.findById(41);
}
}
5.测试图解
1.Mybatis 二级缓存
Mybatis中的一级缓存和二级缓存
一级缓存:
它指的是Mybatis中SqlSession对象的缓存。
当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中
查询是否有,有的话直接拿出来用。
当SqlSession对象消失时,mybatis的一级缓存也就消失了。
二级缓存:
它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
二级缓存的使用步骤:
第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
第三步:让当前的操作支持二级缓存(在select标签中配置)
首先开启 mybatis 的二级缓存。
- sqlSession1 去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。
- 如果 SqlSession3 去执行相同 mapper 映射下 sql,执行 commit 提交,将会清空该 mapper映射下的二级缓存区域的数据。
- sqlSession2 去查询与 sqlSession1 相同的用户信息,首先会去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
1.接口
接口
/**
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有用户,同时获取到用户下所有账户的信息
* @return
*/
List<User> findAll();
/**
* 根据id查询用户信息
* @param userId
* @return
*/
User findById(Integer userId);
/**
* 更新用户信息
* @param user
*/
void updateUser(User user);
}
2.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-->
<properties resource="jdbcConfig.properties"></properties>
<!--开启二级缓存步骤一:
因为cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为
false 代表不开启二级缓存。
-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
<typeAliases>
<package name="com.ginger.pojo"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置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>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.ginger.dao"></package>
</mappers>
</configuration>
3.IUserDao.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">
<mapper namespace="com.ginger.dao.IUserDao">
<!--开启二级缓存步骤二:
<cache>标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。
-->
<cache></cache>
<!-- 查询所有 -->
<select id="findAll" resultType="user">
select * from user
</select>
<!-- 根据id查询用户 -->
<!--开启二级缓存步骤三:
将 UserDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用
二级缓存,如果不使用二级缓存可以设置为 false。
注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。
-->
<select id="findById" parameterType="int" resultType="user" useCache="true">
select * from user where id = #{uid}
</select>
<!-- 更新用户信息-->
<update id="updateUser" parameterType="user">
update user set username=#{username},address=#{address} where id=#{id}
</update>
</mapper>
4.二级缓存测试
public class SecondLevelCache {
InputStream inputStream;
SqlSessionFactory sqlSessionFactory;
@Before//用于在测试方法执行之前执行
public void init() throws Exception {
//1.读取配置文件,生成字节输入流
inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.获取SessionFactory对象
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
/**
* 开始我是这样测试的,其实是不可以的,要仔细看二级缓存结构图,
* 是在两个SqlSession对象中缓存数据,不是在一个Sql对象中缓存数据,那是一级缓存。
*/
@Test
public void test() {
SqlSession sqlSession = sqlSessionFactory.openSession();
IUserDao userdao = sqlSession.getMapper(IUserDao.class);
User user1 = userdao.findById(41);
//清除sqlSession缓存
sqlSession.close();
User user2 = userdao.findById(41);
}
/**
* 正确的二级欢缓存测试方式
*/
@Test
public void test2() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
IUserDao userdao1 = sqlSession1.getMapper(IUserDao.class);
userdao1.findById(41);
//一级缓存消失
sqlSession1.close();
//sqlSession1.clearCache(); 清除缓存看不到二级缓存
SqlSession sqlSession2 = sqlSessionFactory.openSession();
IUserDao userdao2 = sqlSession2.getMapper(IUserDao.class);
userdao2.findById(41);
}
}
5.测试图解
6.二级缓存注意事项
当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这种就可以使用序列化
方式来保存对象。
/**
* 用户实体类
*/
public class User implements Serializable
Mybatis 注解开发
这几年来注解开发越来越流行,Mybatis 也可以使用注解开发方式,这样我们就可以减少编写 Mapper 映射文件了。本次我们先围绕一些基本的 CRUD 来学习,再学习复杂映射关系及延迟加载。
常用注解:
@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result 一起使用,封装多个结果集
代替的是标签<resultMap>
该注解中可以使用单个@Result 注解,也可以使用@Result 集合
@Results({@Result(),@Result()})或@Results(@Result())
@Resutl 注解
代替了 <id>标签和<result>标签
@Result 中 属性介绍:
id 是否是主键字段
column 数据库的列名
property 需要装配的属性名
one 需要使用的@One 注解(@Result(one=@One)()))
many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一)
代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@One 注解属性介绍:
select 指定用来多表查询的 sqlmapper
fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。
使用格式:
@Result(column=" ",property="",one=@One(select=""))
@Many 注解(多对一)
代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType
(一般为 ArrayList)但是注解中可以不定义;
使用格式:
@Result(property="",column="",many=@Many(select=""))
@ResultMap:实现引用@Results 定义的封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用
1.Mybatis CRUD注解开发
1.接口
*/
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
@Select("select * from user")
List<User> findAll();
/**
* 保存用户
* @param user
*/
@Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")
void saveUser(User user);
/**
* 更新用户
* @param user
*/
@Update("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}")
void updateUser(User user);
/**
* 删除用户
* @param userId
*/
@Delete("delete from user where id=#{id} ")
void deleteUser(Integer userId);
/**
* 根据id查询用户
* @param userId
* @return
*/
@Select("select * from user where id=#{id} ")
User findById(Integer userId);
/**
* 根据用户名称模糊查询
* @param username
* @return
*/
//@Select("select * from user where username like #{username} ")
@Select("select * from user where username like '%${value}%' ")
List<User> findUserByName(String username);
/**
* 查询总用户数量
* @return
*/
@Select("select count(*) from user ")
int findTotalUser();
}
2.配置文件
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.itheima.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="com.itheima.dao.IUserDao"></mapper>
</mappers>
</configuration>
jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis
jdbc.username=root
jdbc.password=root
3.测试
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(60);
user.setUsername("刀锋之影");
user.setAddress("诺克萨斯");
user.setSex("男");
user.setBirthday(new Date());
userDao.updateUser(user);
}
@Test
public void testDelete(){
userDao.deleteUser(51);
}
@Test
public void testFindOne(){
User user = userDao.findById(57);
System.out.println(user);
}
@Test
public void testFindByName(){
//List<User> users = userDao.findUserByName("%mybatis%");
List<User> users = userDao.findUserByName("mybatis");
for(User user : users){
System.out.println(user);
}
}
@Test
public void testFindTotal(){
int total = userDao.findTotalUser();
System.out.println(total);
}
}
2.Mybatis注解实现复杂关系映射开发(注解配置延时加载)
1.接口
public interface IAccountDao {
/**
* 查询所有账户
* @return
*/
@Select("select * from account")
@Results(id ="accountMap",value ={
@Result(id = true, property = "id", column = "id"),
@Result(property = "uid", column = "uid"),
@Result(property = "money", column = "money"),
@Result(property = "user", column = "uid",one = @One(select = "com.ginger.dao.IUserDao.findUserById",
fetchType= FetchType.EAGER))
})
List<Account> findAll();
/**
* 根据用户id查询账户信息
* @param userId
* @return
*/
@Select("select * from account where uid = #{userId}")
Account findAccountByUid(Integer userId);
}
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
@Select("select * from user")
@Results(id = "userMap", value = {
@Result(id = true, property = "userId", column = "id"),
@Result(property = "userName", column = "username"),
@Result(property = "userBirthday", column = "birthday"),
@Result(property = "userSex",column = "sex"),
@Result(property = "userAddress",column = "address"),
@Result(property = "accounts", column = "id",many=@Many(select = "com.ginger.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.EAGER))
})
List<User> findAll();
/**
* 根据id查询用户
* @param userId
* @return
*/
@Select("select * from user where id = #{uid}")
@ResultMap("userMap")
User findUserById(Integer id);
}
2.配置文件
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-->
<properties resource="jdbcConfig.properties"></properties>
<!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
<typeAliases>
<package name="com.ginger.pojo"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置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>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.ginger.dao"></package>
</mappers>
</configuration>
jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mybatis
jdbc.username=root
jdbc.password=root
3.测试
public class IAccountTest {
private InputStream in;
private SqlSessionFactory factory;
private SqlSession session;
private IAccountDao accountDao;
@Before
public void init()throws Exception{
in = Resources.getResourceAsStream("SqlMapConfig.xml");
factory = new SqlSessionFactoryBuilder().build(in);
session = factory.openSession();
accountDao = session.getMapper(IAccountDao.class);
}
@After
public void destroy()throws Exception{
session.commit();
session.close();
in.close();
}
@Test
public void test(){
List<Account> accounts = accountDao.findAll();
for (Account account : accounts) {
System.out.println(account);
}
}
}
结果:FetchType.EAGER:表示立即加载
Account{id=1, uid=46, money=1000.0}User{userId=46, userName='格雷福斯', userAddress='班德尔城', userSex='男', userBirthday=Wed Mar 07 17:37:26 CST 2018}[Account{id=1, uid=46, money=1000.0}null, Account{id=3, uid=46, money=2000.0}]
Account{id=2, uid=45, money=1000.0}User{userId=45, userName='影流之主', userAddress='影流', userSex='男', userBirthday=Sun Mar 04 12:04:06 CST 2018}[Account{id=2, uid=45, money=1000.0}]
Account{id=3, uid=46, money=2000.0}User{userId=46, userName='格雷福斯', userAddress='班德尔城', userSex='男', userBirthday=Wed Mar 07 17:37:26 CST 2018}[Account{id=1, uid=46, money=1000.0}null, Account{id=3, uid=46, money=2000.0}]
public class IUserDaoTest {
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 test(){
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
}
结果:FetchType.EAGER:表示立即加载
User{userId=41, userName='男枪', userAddress='征服之海', userSex='男', userBirthday=Wed Jun 10 11:25:58 CST 2020}[]
User{userId=42, userName='诡术妖姬', userAddress='巨龙之巢', userSex='男', userBirthday=Fri Mar 02 15:09:37 CST 2018}[]
User{userId=43, userName='诡术妖姬', userAddress='征服之海', userSex='女', userBirthday=Sun Mar 04 11:34:34 CST 2018}[]
User{userId=45, userName='影流之主', userAddress='影流', userSex='男', userBirthday=Sun Mar 04 12:04:06 CST 2018}[Account{id=2, uid=45, money=1000.0}]
User{userId=46, userName='格雷福斯', userAddress='班德尔城', userSex='男', userBirthday=Wed Mar 07 17:37:26 CST 2018}[Account{id=1, uid=46, money=1000.0}null, Account{id=3, uid=46, money=2000.0}]
User{userId=48, userName='光辉女郎', userAddress='德玛西亚', userSex='女', userBirthday=Thu Mar 08 11:44:00 CST 2018}[]
User{userId=51, userName='亚索', userAddress='雷瑟守备', userSex='男', userBirthday=Wed Jun 10 11:25:58 CST 2020}[]
User{userId=59, userName='维克托', userAddress='祖安', userSex='男', userBirthday=Sat Jun 13 08:50:48 CST 2020}[]
3.Mybatis 基于注解的二级缓存
1.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-->
<properties resource="jdbcConfig.properties"></properties>
<!--开启二级缓存-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!--使用typeAliases配置别名,它只能配置domain中类的别名 -->
<typeAliases>
<package name="com.ginger.pojo"></package>
</typeAliases>
<!--配置环境-->
<environments default="mysql">
<!-- 配置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>
<!-- 配置映射文件的位置 -->
<mappers>
<package name="com.ginger.dao"></package>
</mappers>
</configuration>
2.IUserDao接口中开启二级注解缓存
//开启注解二级缓存
@CacheNamespace(blocking=true)
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
@Select("select * from user")
@Results(id = "userMap", value = {
@Result(id = true, property = "userId", column = "id"),
@Result(property = "userName", column = "username"),
@Result(property = "userBirthday", column = "birthday"),
@Result(property = "userSex",column = "sex"),
@Result(property = "userAddress",column = "address"),
@Result(property = "accounts", column = "id",many=@Many(select = "com.ginger.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.EAGER))
})
List<User> findAll();
/**
* 根据id查询用户
* @param userId
* @return
*/
@Select("select * from user where id = #{uid}")
@ResultMap("userMap")
User findUserById(Integer id);
}
3.测试
public class IUserDaoTest {
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 test() {
User user = userDao.findUserById(41);
SqlSession sqlSession1 = factory.openSession();
IUserDao userdao1 = sqlSession1.getMapper(IUserDao.class);
userdao1.findUserById(41);
}
}