mybatis学习三

1、延迟加载

(1)resultMap可以实现
高级映射,association、collection具有延迟加载的功能;
延迟加载:先从单标查询,需要的时候在从关联表中去查询,能提高数据库的性能;
(2)用association实现延迟加载(用前面一对一查询的例子):
首先定义实体类:
Husband.java:

package cn.melo.bean;

import java.io.Serializable;

public class Husband implements Serializable {
    private Integer hid;
    private String hname;
    private Integer hage;

    private Wife wife;

    public Integer getHid() {
        return hid;
    }

    public void setHid(Integer hid) {
        this.hid = hid;
    }

    public String getHname() {
        return hname;
    }

    public void setHname(String hname) {
        this.hname = hname;
    }

    public Integer getHage() {
        return hage;
    }

    public void setHage(Integer hage) {
        this.hage = hage;
    }

    public Wife getWife() {
        return wife;
    }

    public void setWife(Wife wife) {
        this.wife = wife;
    }

    @Override
    public String toString() {
        return "Husband{" +
                "hid=" + hid +
                ", hname='" + hname + '\'' +
                ", hage=" + hage +
                ", wife=" + wife +
                '}';
    }
}

Wife.java

package cn.melo.bean;

import java.io.Serializable;

public class Wife implements Serializable {
    private Integer wid;
    private String wname;
    private Integer wage;

    public Integer getWid() {
        return wid;
    }

    public void setWid(Integer wid) {
        this.wid = wid;
    }

    public String getWname() {
        return wname;
    }

    public void setWname(String wname){
        this.wname = wname;
    }

    public Integer getWage() {
        return wage;
    }

    public void setWage(Integer wage) {
        this.wage = wage;
    }

    @Override
    public String toString() {
        return "Wife{" +
                "wid=" + wid +
                ", wname='" + wname + '\'' +
                ", wage=" + wage +
                '}';
    }
}

映射配置文件:
HusbandMapper.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="cn.melo.mapper.HusbandMapper">
    <!--id是唯一标识,type是查询的结果类型!-->
    <resultMap id="selectHusband" type="cn.melo.bean.Husband">
        <!--property是bean的属性名,column是属性名对应的字段名-->
        <!--id是表的主键,唯一的字段-->
        <id property="hid" column="hid"/>
        <!--result是表的普通字段-->
        <result property="hname" column="hname"/>
        <result property="hage" column="hage"/>
        <!--select是延迟查询的语句的id,column是延迟查询的关联列-->
        <association property="wife" javaType="cn.melo.bean.Wife" select="cn.melo.mapper.WifeMapper.findWifeById" column="wid">
            <id property="wid" column="wid"/>
            <result property="wname" column="wname"/>
            <result property="wage" column="wage"/>
        </association>
    </resultMap>
    <select id="findHusbandByLazyLoading" resultMap="selectHusband">
        select * from husband where hid = #{hid}
    </select>
</mapper>

WifeMapper.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="cn.melo.mapper.WifeMapper">
    <select id="findWifeById" parameterType="int" resultType="cn.melo.bean.Wife">
        select * from wife where wid = #{id}
    </select>
</mapper>

HusbandMapper.java:

package cn.melo.mapper;

import cn.melo.bean.Husband;

public interface HusbandMapper {
    public Husband findHusbandByLazyLoading(Integer hid);
}

WifeMapper.java:

package cn.melo.mapper;

import cn.melo.bean.Wife;

public interface WifeMapper {
    public Wife findWifeById(Integer wid);
}

测试代码:

//得到代理对象
HusbandMapper husbandMapper = session.getMapper(HusbandMapper.class);
//调用方法
Husband husband = husbandMapper.findHusbandByLazyLoading(1);
//这里只查询了husband的信息
System.out.println(husband.getHname());

在mybatis中,延迟加载默认是关闭的,所以我们想要使用就首先要打开延迟加载,这里先测试还没有打开延迟加载时的效果:
在这里插入图片描述
可以从日志看出,我们没有查询Wife的相关信息,但是还是发送了sql语句去查询Wife的相关信息;
这时我们在全局配置文件中打开延迟加载再来试一下:

<settings>
	<!--打开延迟加载-->
	<setting name="lazyLoadingEnabled" value="true"/>
	<!--关闭积极加载-->
	<setting name="aggressiveLazyLoading" value="false"/>
	</settings>

在这里插入图片描述
此时我们发现它只查询了Husband的信息,只发送了一个sql语句;
此时,我们再次修改测试代码:

//得到代理对象
HusbandMapper husbandMapper = session.getMapper(HusbandMapper.class);
//调用方法
Husband husband = husbandMapper.findHusbandByLazyLoading(1);
System.out.println(husband.getHname());
System.out.println(husband.getWife());

执行结果:
在这里插入图片描述
可以发现当它执行System.out.println(husband.getHname());这句代码的时候发送了sql语句去查询Husband的信息,并打印了出来;程序继续执行,当它执行到System.out.println(husband.getWife());这句代码的时候,再发送sql语句去查询Wife的相关信息;这就是延迟加载,也就是说在你需要该信息的时候才会去发送sql语句去查询相应的信息!

(3)用collection实现延迟加载(用前面的老师对应学生的案列):
实体类:
Stu.java:

package cn.melo.bean;

public class Stu {
    private Integer sid;
    private String sname;
    private Integer sage;
    private Integer tid;

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Integer getSage() {
        return sage;
    }

    public void setSage(Integer sage) {
        this.sage = sage;
    }

    public Integer getTid() {
        return tid;
    }

    public void setTid(Integer tid) {
        this.tid = tid;
    }

    @Override
    public String toString() {
        return "Stu{" +
                "sid=" + sid +
                ", sname='" + sname + '\'' +
                ", sage=" + sage +
                ", tid=" + tid +
                '}';
    }
}

Teacher.java

package cn.melo.bean;

import java.util.List;

public class Teacher {
    private Integer tid;
    private String tname;
    private Integer tage;

    List<Stu> stus;

    public Integer getTid() {
        return tid;
    }

    public void setTid(Integer tid) {
        this.tid = tid;
    }

    public String getTname() {
        return tname;
    }

    public void setTname(String tname) {
        this.tname = tname;
    }

    public Integer getTage() {
        return tage;
    }

    public void setTage(Integer tage) {
        this.tage = tage;
    }

    public List<Stu> getStus() {
        return stus;
    }

    public void setStus(List<Stu> stus) {
        this.stus = stus;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "tid=" + tid +
                ", tname='" + tname + '\'' +
                ", tage=" + tage +
                ", stus=" + stus +
                '}';
    }
}

映射配置文件:
StuMapper.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="cn.melo.mapper.StuMapper">
    <select id="findStudentsByTid" resultType="cn.melo.bean.Stu">
        SELECT * from stu where tid=#{id}
    </select>
</mapper>

TeacherMapper.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="cn.melo.mapper.TeacherMapper">
    <!--id是唯一标识,type是查询的结果类型!-->
    <resultMap id="selectTeacherAndStudents" type="cn.melo.bean.Teacher">
        <!--property是bean的属性名,column是属性名对应的字段名-->
        <!--id是表的主键,唯一的字段-->
        <id property="tid" column="tid"/>
        <!--result是表的普通字段-->
        <result property="tname" column="tname"/>
        <result property="tage" column="tage"/>
        <!--collection是一对多对应的bean属性-->
        <collection property="stus" ofType="cn.melo.bean.Stu" select="cn.melo.mapper.StuMapper.findStudentsByTid" column="tid">
            <id property="sid" column="sid"/>
            <result property="sname" column="sname"/>
            <result property="sage" column="sage"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
    <select id="findTeacherByLazyLoading" resultMap="selectTeacherAndStudents">
        SELECT * from teacher where tid=#{id}
    </select>
</mapper>

接口:略
测试代码:

//得到代理对象
TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
//调用方法
Teacher teacher = teacherMapper.findTeacherByLazyLoading(1);
System.out.println(teacher.getTname());

查询结果,这里我还没有打开延迟加载:
在这里插入图片描述
打开延迟加载后的查询结果:
在这里插入图片描述
修改测试代码,打开延迟加载的结果:
测试代码:java

//得到代理对象
TeacherMapper teacherMapper = session.getMapper(TeacherMapper.class);
//调用方法
Teacher teacher = teacherMapper.findTeacherByLazyLoading(1);
System.out.println(teacher.getTname());
System.out.println(teacher.getStus());

在这里插入图片描述
可见还是在需要数据的时候才会去发送sql语句去查询数据库!!!

2、查询缓存:

mybatis中的缓存分为一级缓存和二级缓存,缓存就是第一次查找时,会去数据库中查找数据,第二次查找时,如果缓存中有数据,就不会再去数据库中查数据,直接从缓存中取数据即可,能提高系统的性能;
(1)一级缓存是sqlSession级别的缓存,在操作数据库时需要SqlSession对象,在对象中有一个HashMap用于存储缓存数据,不同的SqlSession对象之间的缓存数据区域(HashMap)互相不影响!如果中间对数据进行了增删改操作,缓存区就会清空!
验证:
映射配置文件:

<?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="cn.melo.mapper.UserMapper">
    <select id="findUserById" parameterType="int" resultType="cn.melo.bean.User">
        select * from user where id = #{id}
    </select>
    <update id="updateUser" parameterType="int">
        update user set password = 'melo'
    </update>
</mapper>

测试代码:

//得到代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);

//查询
User user = userMapper.findUserById(1);
System.out.println(user);

User user1 = userMapper.findUserById(1);
System.out.println(user1);

结果:
在这里插入图片描述
可以看出,第一次是向数据库中发送了查询语句的,但是第二次查询相同的内容时没有!

修改测试代码:

//得到代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);

//查询
User user = userMapper.findUserById(1);
System.out.println(user);
//进行一次更新操作
userMapper.updateUser(2);

User user1 = userMapper.findUserById(1);
System.out.println(user1);

结果:
在这里插入图片描述
可以看出,我们在中间进行了一次更新操作,虽然更新的不是我们查询的对象,但是,再两次查询同一个内容的时候,还是发送了两次sql语句,也就是说,在执行更新操作的时候,缓存中的内容被清空了!

(2)二级缓存是mapper级别的缓存,多个sqlSession去操作同一个mapper的sql语句时可以共用二级缓存,二级缓存是跨sqlSession的;如果中间有某一个sqlSession执行了增删改并且提交了数据(Commit),就会清空缓存!
想使用二级缓存时要让查询的对象实现序列化接口哦,不然会报错:
java.io.NotSerializableException: cn.melo.bean.User

mybatis中的二级缓存默认是关闭的,使用前需要先去打开:
全局配置文件中:

<settings>
	<!--开启二级缓存-->
	<setting name="cacheEnabled" value="true"/>
</settings>

映射配置文件:
在这里插入图片描述

验证:
映射配置文件和接口和上面是一样的,只改变测试代码:
测试代码:

//得到会话对象
SqlSession session = factory.openSession();
//得到代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);

//查询
User user = userMapper.findUserById(2);
System.out.println(user);

//提交
session.commit();
//释放
session.close();

SqlSession session1 = factory.openSession();
UserMapper userMapper1 = session1.getMapper(UserMapper.class);

User user1 = userMapper1.findUserById(2);
System.out.println(user1);
//提交和释放资源
session1.commit();
session1.close();

结果:
在这里插入图片描述
可以看出,虽然我们用了两个不同的sqlSession,但是是在同一个mapper下查询相同的数据,所以第一次查询向数据库发送了语句,第二次却没有,说明第二次是从缓存区中取出的数据!

修改一下测试代码,这次中间有一个新的sqlSession对数据进行了更新操作,并且提交了数据:

//得到会话对象
SqlSession session = factory.openSession();
//得到代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);

//查询
User user = userMapper.findUserById(2);
System.out.println(user);

//提交
session.commit();
//释放
session.close();

//用一个新的sqlSession进行一次更新操作
SqlSession session2 = factory.openSession();
UserMapper userMapper2 = session2.getMapper(UserMapper.class);
userMapper2.updateUser(6);
session2.commit();
session2.close();

SqlSession session1 = factory.openSession();
UserMapper userMapper1 = session1.getMapper(UserMapper.class);

User user1 = userMapper1.findUserById(2);
System.out.println(user1);
//提交和释放资源
session1.commit();
session1.close();

结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以发现两次都向数据库发送了sql语句去查询,说明在执行更新操作的时候,清空了缓存区!!!

(3)如果要想自定义缓存,实现自己的缓存逻辑,那么mybatis提供了一个借口Cache,只需要实现这个接口即可!!!

因为mybatis无法实现分布式缓存,所以当它整合其他分布式框架的时候,其他的分布式框架就会提供Cache接口的实现类!!!!

3、逆向工程生成java文件:

!!!!!针对单表
逆向工程就是根据已有的数据库表自动生成相关的实体类,mapper接口和映射配置文件!!
操作步骤:
导入jar包:mybatis-generator-core-xxx.jar以及其他mybatis相关的jar包!
(1)在src同级目录创建逆向工程配置文件(放在项目下,即和src同级,名随意):
generatorConfig.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
  <context id="DB2Tables" targetRuntime="MyBatis3">
  	<!-- 指定数据源 -->
    <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
        connectionURL="jdbc:mysql:///mybatis?serverTimezone=GMT%2b8&amp;characterEncoding=utf8"
        userId="root"
        password="123">
    </jdbcConnection>
    
    

    <javaTypeResolver >
   		 <!--是否将护具库中的int和double数据类型转化为BigDecimal类型  -->
      <property name="forceBigDecimals" value="false" />
    </javaTypeResolver>

	<!-- 生成实体类的包 -->
    <javaModelGenerator targetPackage="cn.melo.bean" targetProject=".\src">
      <property name="enableSubPackages" value="true" />
      <property name="trimStrings" value="true" />
    </javaModelGenerator>
	
	<!-- 指定生成的mapper.xml的路径包 -->
    <sqlMapGenerator targetPackage="cn.melo.mapper"  targetProject=".\src">
      <property name="enableSubPackages" value="true" />
    </sqlMapGenerator>

	<!-- 指定生成mapper接口的路径包 -->
    <javaClientGenerator type="XMLMAPPER" targetPackage="cn.melo.mapper"  targetProject=".\src">
      <property name="enableSubPackages" value="true" />
    </javaClientGenerator>
    
    <!-- 指定表名 -->
    <table tableName="t_user"></table>

  </context>
</generatorConfiguration>

(2)在src下,你只需要写一段测试代码,并执行之,就会自动生成实体类文件和映射配置文件以及接口和他们对应的包:
测试代码:

package cn.melo.test;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

public class Demo1 {
	@Test
	public void test() throws Exception {
		List<String> warnings = new ArrayList<String>();
		boolean overwrite = true;
		File configFile = new File("generatorConfig.xml");
		ConfigurationParser cp = new ConfigurationParser(warnings);
		Configuration config = cp.parseConfiguration(configFile);
		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
		myBatisGenerator.generate(null);
	}
}

执行测试代码,刷新一下项目就会出现生成的文件了!!!
在这里插入图片描述

3、逆向工程对单表的CRUD操作:

这时候就不用去写映射配置文件了,因为逆向工程已经帮你生成了!
所以在直接调用逆向工程生成的接口中的方法即可:
添加操作:

//加载配置文件
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//得到sqlSession工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//得到SqlSession对象
SqlSession session = factory.openSession();

//得到代理对象
TUserMapper tUserMapper = session.getMapper(TUserMapper.class);

TUser tuser = new TUser();
tuser.setUid(3);
tuser.setUname("韦德");
tuser.setUage(20);
tuser.setUgender("男");
//调用添加方法
tUserMapper.insert(tuser);

session.commit();
session.close();

根据id删除操作:

//得到代理对象
TUserMapper tUserMapper = session.getMapper(TUserMapper.class);

//调用删除方法
tUserMapper.deleteByPrimaryKey(3);

//或者是通过Example给出条件删除
//TUserExample userExample = new TUserExample();
//Criteria criteria = userExample.createCriteria();
//添加条件
//criteria.andUidEqualTo(3);

//tUserMapper.deleteByExample(userExample);

session.commit();
session.close();

修改:

//得到代理对象
TUserMapper tUserMapper = session.getMapper(TUserMapper.class);

TUser tuser = new TUser();
tuser.setUid(1);
tuser.setUname("Anthony");
tuser.setUage(21);
tuser.setUgender("男");
//调用更新方法
//tUserMapper.updateByPrimaryKey(tuser);
//或者用TUserExample封装条件来修改
/*
TUserExample userExample = new TUserExample();
Criteria criteria = userExample.createCriteria();
criteria.andUidEqualTo(1);
tUserMapper.updateByExample(tuser, userExample);
*/

查询,注意只能查询所有列!!

//得到代理对象
TUserMapper tUserMapper = session.getMapper(TUserMapper.class);

//通过id查询
TUser user = tUserMapper.selectByPrimaryKey(1);
System.out.println(user.getUname());

//或者是通过Example给出条件查询
TUserExample userExample = new TUserExample();
Criteria criteria = userExample.createCriteria();
//添加条件,如模糊查询名字中含o的人(模糊查询)
criteria.andUnameLike("%o%");


List<TUser> list = tUserMapper.selectByExample(userExample);
for (TUser tUser : list) {
System.out.println(tUser.getUname());
}

session.commit();
session.close();

附:mybatis的配置文件:
数据库连接配置文件(db.properties):

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb?serverTimezone=GMT%2b8&characterEncoding=utf-8
jdbc.username=root
jdbc.password=123

全局配置文件:

<?xml version="1.0" encoding="utf-8"?>
<!-- 引入dtd约束 -->
<!DOCTYPE configuration
       PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
   <!-- 引入外部属性配置文件或者定义属性 -->
   <properties resource="db.properties"></properties>
   <settings>
       <!--打开延迟加载-->
       <setting name="lazyLoadingEnabled" value="true"/>
       <!--关闭积极加载-->
       <setting name="aggressiveLazyLoading" value="false"/>

       <!--开启二级缓存-->
       <setting name="cacheEnabled" value="true"/>
   </settings>
   <!-- 配置数据库相关信息 -->
   <environments default="development">
       <environment id="development">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <property name="driver" value="${jdbc.driver}"/>
               <property name="url" value="${jdbc.url}"/>
               <property name="username" value="${jdbc.username}"/>
               <property name="password" value="${jdbc.password}"/>
           </dataSource>
       </environment>
   </environments>
   <mappers>
       <!-- 批量引入映射配置文件 -->
       <package name="cn.melo.mapper"/>
   </mappers>
</configuration>

映射配置文件:

<?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="cn.melo.mapper.XxxMapper">
   <select id="xx" parameterType="int" resultType="cn.melo.bean.Xxx">
       select * from xx where id = #{id}
   </select>
</mapper>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值