MyBatis-3

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);
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值