一对一查询
第一种,用拓展类的方式
需要一对一查询Course和Teacher两个表
新建一个类,继承Course类,然后将Teacher类中的属性加到这个新类中,还需要有get和set方法
之后用debug查看
package com.zym.pojo; public class ct extends Course{ // private String t_id; private String t_name; // @Override //// public String getT_id() { //// return t_id; //// } // // @Override // public void setT_id(String t_id) { // this.t_id = t_id; // } public String getT_name() { return t_name; } public void setT_name(String t_name) { this.t_name = t_name; } }
第二种使用resultMap
使用resultMap,定义专门的resultMap用于映射一对一查询结果。
在一个类中,添加另一个类的对象属性,并设置get set方法
public class Teacher { private String t_id; private String t_name; private Course Course; public Course getCourse() { return Course; } public void setCourse_obj(Course course_obj) { Course = course_obj; }
xml
<resultMap id="Teacher_map" type="Teacher"> <id property="t_id" column="t_id"/> <result property="t_name" column="t_name"/> <association property="Course" javaType="Course"> <id property="t_id" column="t_id"/> <result property="c_name" column="c_name"/> <result property="c_id" column="c_id"/> </association> </resultMap> <select id="select_onebyone_map" resultMap="Teacher_map"> SELECT c_name,t_name,c.c_id,t.t_id,c.t_id FROM Course c LEFT JOIN Teacher t on c.t_id=t.t_id; </select>
一对多
student和score的一对多
public class Student { private Integer s_id; private String s_name; private Date s_birth; private String s_sex; private List<Score> Scores; public List<com.zym.pojo.Score> getScore() { return Scores; } public void setScore(List<com.zym.pojo.Score> score) { Scores = score; }
xml
<resultMap id="stu_score_map" type="Student"> <id property="s_id" column="s_id"/> <result property="s_name" column="s_name"/> <result property="s_birth" column="s_birth"/> <result property="s_sex" column="s_sex"/> <collection property="Scores" javaType="List" ofType="Score"> <id property="s_id" column="s_id_2"/> <result property="s_score" column="s_score"/> <result property="c_id" column="c_id"/> </collection> </resultMap> <select id="select_ones_score" resultMap="stu_score_map"> SELECT s_name,stu.s_id,sco.s_id as sco_s_id,s_sex,s_score FROM Student stu LEFT JOIN Score sco on stu.s_id=sco.s_id </select>
多对多关系
public class Goods { private Integer id; private String gname; private Double price; private String gtype; //多对多 private List<Order> order;
public class Order implements Serializable{ private Integer id; private Integer userId; private Integer number; private Date createtime; private String note; // 一对一 private User user; // 多对多 private List<Goods> listgoods;
xml
<mapper namespace="com.jy.mapper.UserMapper"> <!-- mang2mang 订单和商品信息 --> <resultMap type="Order" id="orderandgoodsmap"> <!-- 主键映射关系 --> <id property="id" column="oid"/>/映射中间表 <result property="createtime" column="createtime"/> <result property="number" column="number"/> <collection property="listgoods" javaType="list" ofType="goods"> <!-- 主键映射关系 --> <id property="id" column="gid"/> /映射中间表 <result property="gname" column="gname"/> <result property="gtype" column="gtype"/> </collection> </resultMap> <select id="selectOrderAndGoods" resultMap="orderandgoodsmap"> select o.id oid,o.createtime,o.number,g.id gid,g.gname,g.gtype from t_goods g,t_order o,order_goods og where g.id=og.gid and o.id=og.oid </select>
使用mybatis插件进行自动生成关系
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> <!--导入属性配置--> <properties resource="jdbc.properties"></properties> <!-- 指定数据库驱动的jdbc驱动jar包的位置 --> <!--<classPathEntry location="${db.driverLocation}" />--> <!-- context 是逆向工程的主要配置信息 --> <!-- id:起个名字 --> <!-- targetRuntime:设置生成的文件适用于那个 mybatis 版本 --> <context id="default" targetRuntime="MyBatis3"> <!--optional,旨在创建class时,对注释进行控制--> <commentGenerator> <property name="suppressDate" value="true" /> <!-- 是否去除自动生成的注释 true:是 : false:否 --> <property name="suppressAllComments" value="true" /> </commentGenerator> <!--jdbc的数据库连接--> <jdbcConnection driverClass="${db.driverClassName}" connectionURL="${db.url}" userId="${db.username}" password="${db.password}"> </jdbcConnection> <!--非必须,类型处理器,在数据库类型和java类型之间的转换控制--> <javaTypeResolver> <!-- 默认情况下数据库中的 decimal,bigInt 在 Java 对应是 sql 下的 BigDecimal 类 --> <!-- 不是 double 和 long 类型 --> <!-- 使用常用的基本类型代替 sql 包下的引用类型 --> <property name="forceBigDecimals" value="false" /> </javaTypeResolver> <!-- targetPackage:生成的实体类所在的包 --> <!-- targetProject:生成的实体类所在的硬盘位置 --> <javaModelGenerator targetPackage="com.zym.pojo" targetProject=".\src\main\java"> <!-- 是否允许子包 --> <property name="enableSubPackages" value="false" /> <!-- 是否对modal添加构造函数 --> <property name="constructorBased" value="true" /> <!-- 是否清理从数据库中查询出的字符串左右两边的空白字符 --> <property name="trimStrings" value="true" /> <!-- 建立modal对象是否不可改变 即生成的modal对象不会有setter方法,只有构造方法 --> <property name="immutable" value="false" /> </javaModelGenerator> <!-- targetPackage 和 targetProject:生成的 mapper 文件的包和位置 --> <sqlMapGenerator targetPackage="com.zym.mapper" targetProject=".\src\main\java"> <!-- 针对数据库的一个配置,是否把 schema 作为字包名 --> <property name="enableSubPackages" value="false" /> </sqlMapGenerator> <!-- targetPackage 和 targetProject:生成的 interface 文件的包和位置 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.zym.mapper" targetProject=".\src\main\java"> <!-- 针对 oracle 数据库的一个配置,是否把 schema 作为字包名 --> <property name="enableSubPackages" value="false" /> </javaClientGenerator> <table tableName="user" > <!--enableCountByExample="false" enableUpdateByExample="false"--> <!--enableDeleteByExample="false" enableSelectByExample="false"--> <!--selectByExampleQueryId="false">--> </table> <table tableName="Student"></table> <table tableName="Score"></table> <table tableName="Teacher"></table> </context> </generatorConfiguration>
之后直接在运行插件,但是这个值对应生成一张表的查询,无法解决一对一,一对多,和多对多关系。
使用方法:
public void mybatis_plugin_test() throws IOException { init(); SqlSession sqlSession = this.sqlSessionFactory.openSession(); Object mapper = sqlSession.getMapper(StudentMapper.class); List<Student> students = ((StudentMapper) mapper).selectByExample(null); System.out.println(students.size()); StudentExample st = new StudentExample(); // st.createCriteria().andSNameLike("%李%"); // List<Student> studentList = ((StudentMapper) mapper).selectByExample(st); // System.out.println(studentList); st.createCriteria().andSIdEqualTo("01");//支持链式操作 List<Student> students1 = ((StudentMapper) mapper).selectByExample(st); System.out.println(students1); } }
什么是查询缓存
Mybatis的一级缓存
是指SqlSession。一级缓存的作用域是一个SqlSession。Mybatis默认开启一级缓存。
在同一个SqlSession中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则SqlSession的缓存清空。
Mybatis的二级缓存
是指mapper映射文件。二级缓存的作用域是同一个namespace下的mapper映射文件内容,多个SqlSession共享。Mybatis需要手动设置启动二级缓存。(二级缓存是SqlSessionFactory级别的缓存)
在同一个namespace下的mapper文件中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存中;第二次直接从缓存中取。当执行SQL时两次查询中间发生了增删改操作,则二级缓存清空。
二级存使用范围:如果项目中的表数据允许出现少量的冗余数据,或者是只读数据;可以把这些数据放到二级缓存;
一级缓存原理
一级缓存区域是根据SqlSession为单位划分的。
每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。
SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。
二级缓存原理
二级缓存是mapper级别的。Mybatis默认是没有开启二级缓存。
第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内。
第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息。会去对应的二级缓存内取结果。
如果调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操作。此时会清空该namespace下的二级缓存。
开启二级缓存
1、 在核心配置文件SqlMapConfig.xml中加入以下内容(开启二级缓存总开关):
cacheEnabled设置为 true
2、在映射文件中,加入以下内容,开启二级缓存:
<!-- 开启二级缓存 -->
<!-- 单位:毫秒 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<property name="timeToIdleSeconds" value="12000"/>
<property name="timeToLiveSeconds" value="3600"/>
<!-- 同ehcache参数maxElementsInMemory -->
<property name="maxEntriesLocalHeap" value="1000"/>
<!-- 同ehcache参数maxElementsOnDisk -->
<property name="maxEntriesLocalDisk" value="10000000"/>
<property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>
实现序列化
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。
如果该类存在父类,那么父类也要实现序列化。
禁用二级缓存
该statement中设置userCache=false可以禁用当前select语句的二级缓存,即每次查询都是去数据库中查询,默认情况下是true,即该statement使用二级缓存。
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!--diskStore:缓存数据持久化的目录 地址 -->
<diskStore path="E:\develop\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
diskPersistent="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
懒加载
resultMap中的association和collection标签具有延迟加载的功能。
延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。使用关联信息时再去加载关联信息。
设置延迟加载
立即加载
需要在SqlMapConfig.xml文件中,在<settings>标签中设置下延迟加载。
lazyLoadingEnabled、aggressiveLazyLoading
设置项 |
描述 |
允许值 |
默认值 |
lazyLoadingEnabled |
全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。 |
true | false |
false |
aggressiveLazyLoading |
当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。 |
true | false |
true |
|
<!—延迟加载 -->
<select id="selectOrderById" resultMap="ordrermap">
select * from orders
</select>
<resultMap type="order" id="ordrermap">
<id property="id" column="id"/>
<result property="number" column="number"/>
<association property="user" javaType="user" column="user_id" select="selectUseByUserid">
</association>
</resultMap>
<select id="selectUseByUserid" resultType="user">
select * from t_user where id=#{id}
</select>