Mybatis
2021-10-14 14:35:20 32 举报
AI智能生成
Mybatis
作者其他创作
大纲/内容
多表查询
一对一(多对一)
举例
举例:<br> 人和身份证号就是一对一, 一个人只能有一个身份证号<br> 一个身份证号只能属于一个人<br>特例:<br> 如果拿出每一个账户,他都只能属于一个用户。<br> 所以Mybatis就把多对一看成了一对一。<br>
//从表实体应该包含一个主表实体的<b>对象引用</b><br>Account实体类中含:private User user;
映射文件使用assocation标签
一对多
举例
一个用户可以有多个账户<br> 一个账户只能属于一个用户(多个账户也可以属于同一个用户)
一对多关系映射:主表实体应该包含从表实体的集合引用<br>User实体类中含:private List<account> accounts;</account>
设计步骤
1、建立两张表:用户表,账户表<br> 让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加<br>2、建立两个实体类:用户实体类和账户实体类<br> <b>让用户和账户的实体类能体现出来一对多的关系</b><br>3、建立两个配置文件<br> 用户的配置文件<br> 账户的配置文件<br>4、实现配置:<br> 当我们查询用户时,可以同时得到用户下所包含的账户信息<br> 当我们查询账户时,可以同时得到账户的所属用户信息(一对一)
映射文件代码
<b>collection是用于建立一对多中集合属性的对应关系,property值为主表中集合引用的名字 ofType用于指定集合元素的数据类型<br>UserDao.xml</b><br><resultMap id="userAccountMap" type="com.aaa.domain.User"><br> <id property="userId" column="id"></id><br> ......<br> <result property="userBirthday" column="birthday"></result><br> <b><collection property="accounts" ofType="account"><br> <id property="id" column="aid"></id><br>注意从表的column值不能与主表的id一样,否则会出现封装为null值,需要起别名<br> <result property="uid" column=<font color="#ffb74d">"uid"</font>></result><br> <result property="money" column="money"></result><br> </collection></b><br> </resultMap>
多对多
举例
用户和角色<br> 一个用户可以有多个角色<br> 一个角色可以赋予多个用户<br>
//多对多关系映射:各自包含对方一个集合引用 <br>User实体类中含:private List<Role> roles;<br>Account实体类中含:private List<User> users;
设计步骤
1、建立两张表:用户表,角色表<br> 让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含各自的主键,在中间表中是外键。<br>2、建立两个实体类:用户实体类和角色实体类<br> 让用户和角色的实体类能体现出来多对多的关系<br> <b>各自包含对方一个集合引用</b><br>3、建立两个配置文件<br> 用户的配置文件<br> 角色的配置文件<br>4、实现配置:<br> 当我们查询用户时,可以同时得到用户所包含的角色信息<br> 当我们查询角色时,可以同时得到角色的所赋予的用户信息
映射文件代码
同一对多<br>在UserDao.xml和AccountDao.xml都需要写<collection>标签<br>注意:实体类名和数据库名如果不一致 要定义ResultMap<br>表之间的column值不能一致,否则会出现封装为null值,需要起别名<br>
连接池与事务深入
MyBatis使用自己的数据源
UNPOOLED 不使用连接池的数据源
POOLED 使用连接池的数据源
JNDI 使用JNDI实现的数据源
事务
Mybatis中事务的提交方式,本质上就是调用JDBC的setAutoCommit()来实现事务控制
MyBatis默认手动提交事务
增删改都要session.commit()
开启自动提交事务
session = factory.openSession(true);
MyBatis查询缓存
说明
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybaits提供一级缓存,和二级缓存。
一级缓存
工作原理
使用场景
二级缓存
工作原理
分支主题
说明
二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。
二级缓存是以序列化的形式存储的,存放的内容是数据而不是对象,所以通过两个不同session对象得到的dao结果集不等
开启二级缓存
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。
禁用二级缓存
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
&lt;select id=&quot;findOrderListResultMap&quot; resultMap=&quot;ordersUserMap&quot; useCache=&quot;false&quot;&gt;
刷新缓存
在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
设置statement配置中的flushCache=&quot;true&quot; 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
&lt;insert id=&quot;insertUser&quot; parameterType=&quot;com.mybaits.entity.User&quot; flushCache=&quot;true&quot;&gt;
Mybatis Cache参数
lushInterval(刷新间隔)
可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)
可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。
readOnly(只读)
可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
eviction(收回策略)
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
示例
二级缓存应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,
业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
二级缓存的局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好
MyBatis延迟加载
延迟加载
优点
在需要用到数据时才进行加载,不需要用到数据时就不加载数据。<br>延迟加载也称懒加载. <br>好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,<br>因为查询单表要比关联查询多张表速度要快
缺点
因为只有当需要用到数据时,才会进行数据库查询,<br>这样在大批量数据查询时,因为查询工作也要消耗时间,<br>所以可能造成用户等待时间变长,造成用户体验下降
一对多,多对多:通常情况下我们都是采用延迟加载。<br> 多对一,一对一:通常情况下我们都是采用立即加载。<br>
实现
一对一延迟加载
使用association中的select指定延迟加载去执行的statement的映射id(即唯一标识)
<!-- 它是用于指定从表方的引用实体属性的 --><br><b>column : 填写我们要传递给 select 映射的参数</b><br><association <br> property="user" <br> javaType="user" <br> select="com.google.dao.UserDao.findById" <br> column="uid"><br></association><br>
一对多延迟加载
使用collection中的select指定延迟加载去执行的statement的映射id
<!-- collection 是用于建立一对多中集合属性的对应关系<br> <b>ofType 用于指定集合元素的数据类型<br> select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称)<br> column 是用于指定使用哪个字段的值作为条件查询</b><br>--><br><collection <br> property="accounts" <br> ofType="account" <br> select="com.google.dao.AccountDao.findByUid"<br> column="id"><br></collection><br>
使用association实现延迟加载
使用association中的select指定延迟加载去执行的statement的id。
在mybatis核心配置文件中的配置
mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。
基本步骤
1.加入maven依赖
2.创建Dao接口:定义了操作数据库的方法
3.创建mapper文件,也叫sql映射文件:写sql语句的,和接口方法对应的sql语句
4.创建mybatis的主配置文件:1)连接数据库 2)指定mapper文件的位置(target/classes下)
5.使用Mybatis的对象 SqlSession执行sql语句
CRUD
增强的jdbc,访问数据库,执行crud
使用配置文件xml开发
模糊查询
<!-- "%"#{username}"%" 只能用双引号<br> 或者用like concat('%', #{username},'%')<br> -->
自己实现Dao
使用动态代理Dao
注解开发
注意:一个Dao中只能选择一种开发方式,要使用注解开发,则该dao目录下不能含有xml文件
常用注解
@Insert:实现新增<br>@Update:实现更新 <br>@Delete:实现删除 <br>@Select:实现查询 <br>@Result:实现结果集封装<br>@Results:可以与<br>@Result 一起使用,封装多个结果集<br>@ResultMap:实现引用<br>@Results 定义的封装<br>@One:实现一对一结果集封装 <br>@Many:实现一对多结果集封装<br>@SelectProvider: 实现动态 SQL 映射<br>@CacheNamespace:实现注解二级缓存的使用<br>
实体类名与数据库名不一致
@Result:实现结果集封装<br>@Results:可以与<br>@ResultMap:实现引用<br>
代码
多表查询
一对一
关系映射:实体类从表方应该包含一个主表方的对象引用
使用@One<br>select:唯一标识<br>fetchType:LAZY(延迟加载),EAGER(立即加载),DEFAULT
一对多
关系映射:实体类包含一个对方的对象集合引用
使用@Many<br>select:唯一标识<br>column:数据库表主键名称<br>fetchType:
多对多
关系映射:实体类各自包含一个对方的对象集合引用
使用@Many<br>select:唯一标识<br>column:数据库表主键名称<br>fetchType:
一级缓存默认开启
开启二级缓存
1.主配置文件配置setting
<settings><br> <!--开启二级缓存--><br> <setting name="cacheEnabled" value="true"/><br></settings>
2.Dao接口使用@CacheNamespace注解
使用动态代理Dao完成CRUD
动态代理:mybatis自动创建dao接口的实现类,在实现类中调用SqlSession执行sql语句
使用动态代理的方式
1.获取SqlSession对象,SqlSessionFactory.openSession()
2.使用sqlSession.getMapper(接口.class)方法获取某个接口的对象
3.使用Dao接口的方法,调用方法就执行了mapper文件中sql语句
使用动态代理方式的要求
1.Dao接口和mapper文件放在一起,同一个目录
2.Dao接口和mapper文件名称一致
3.mapper文件中的namespace的值是dao接口的全限定名称
4.mapper文件中的<select>,<insert><update><delete>等的id是接口的方法名称
5.Dao接口中不要使用重载方法,不要使用同名的,不同参数的方法
理解传参
从java代码把实际的值传入到mapper中
1.一个简单类型的参数:#{任意字符}
2.多个简单类型的参数:使用@Param("自定义名称")
3.使用一个java对象,对象的属性值作为mapper文件找到参数,#{java对象的属性名}
4.使用参数的位置,语法#{arg0},#{arg1}
5.使用Map作为参数,#{map的key}
#和$的区别
1.#是占位符,表示列值的,放在等号右侧
2.$也是占位符,表示字符串的连接,把sql语句连接成一个字符串
3.#占位符使用的jdbc指定PrepareStatement对象执行sql语句,效率高,没有sql注入的风险
4.$使用的是Statement执行sql,效率低,有sql注入的风险
mybatis返回结果
resultType
表示sql语句的执行结果,转为java对象的类型
1.实体类对象类型的全限定名称
2.别名,在mybatis主配置文件定义别名
1.使用<typeAlias>
2.使用<package name="包名" />,类名就是别名
resultMap
自定义列名和java实体类对象的属性名对应关系
列名和属性名不一致的解决的方式
使用列名as 别名
使用resultMap
like
在java代码中指定like的内容 ,例如%张%
在mapper文件中拼接like
动态SQL<br>
根据条件,能够得到不同的sql语句,使用mybatis的标签,例如 if,where,foreach等
if
判断条件,条件为true,会把if之间的sql加入到主sql之后
判空和长度<br><if test="username!=null and username != '' "> <br> and username like #{username} <br></if>
where 1=1 的作用
where
<where>标签里面是多个if,如果有一个if判断为true,会在sql的后面加入where关键字,会去掉无用的and,or等字符
<select id="findByCondition" parameterType="user" resultMap="userMap"><br> select * from user<br> <where><br> <if test="userName !=null"><br> and username=#{userName}<br> </if><br> <if test="userSex !=null"><br> and sex=#{userSex};<br> </if><br> </where><br> </select>
foreach
循环数组,list集合
SQL 语句:<br>select 字段 from user where id in (?)<br><foreach>标签用于遍历集合,它的属性:<br> collection:代表要遍历的集合元素,<b>注意编写时不要写#{}</b><br> open:代表语句的开始部分<br> close:代表结束部分 <br> item:代表遍历集合的每个元素,生成的变量名<br> sperator:代表分隔符<br>
代码<br>select * from user<br> <where><br> <if test="ids!=null and ids.size()>0"><br> <foreach collection="ids" open="id in(" close=")" item="uid" separator=","><br> #{uid}<br> </foreach><br> </if><br> </where><br>
抽取sql代码片段:复用部分sql语句
<b><!-- 定义抽取重复的语句代码片段 --></b><br><sql id="defaultSql"> <br> select * from user<br></sql><br>
<b><!-- include标签引用 --></b><br><select id="findById" resultType="user" parameterType="int"><br> <include refid="defaultSql"></include><br> where id = #{uid}<br></select><br>
mybatis配置文件
1.主配置文件SqlMapConfig.xml
SqlMapConfig.xml中配置的内容和顺序
<b>-properties(属性)</b><br> --property<br>-settings(全局配置参数)<br> --setting<br><b>-typeAliases(类型别名)</b><br> --typeAliase<br> --package<br>-typeHandlers(类型处理器)<br>-objectFactory(对象工厂)<br>-plugins(插件)<br>-environments(环境集合属性对象)<br> --environment(环境子属性对象)<br> ---transactionManager(事务管理)<br> ---dataSource(数据源)<br><b>-mappers(映射器)</b><br> --mapper<br> --package<br>
properties(属性)
1.在主配置文件中<dataSource>使用<property>直接指定数据库连接信息
<dataSource type="POOLED"><br> <property name="driver" value="com.mysql.jdbc.Driver"/><br> <property name="url" value="jdbc:mysql://localhost:3306/表名"/><br> <property name="username" value="root"/><br> <property name="password" value="root"/><br></dataSource><br>
2.使用properties配置连接数据库的信息
1.在内部标签配置
<properties><br> <property name="driver" value="com.mysql.jdbc.Driver"/><br> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><br> <property name="username" value="root"/><br> <property name="password" value="root"/><br></properties>
dataSource标签中的property标签value值使用${key名}
2.在resources目录下定义属性配置文件jdbcConfig.properties
resource属性:用于执行配置文件的位置,是按照类路径的写发来写,并且必须存在于类路径下
<properties <b>resources="jdbcConfig.properties"</b>></properties>
dataSource标签中的property标签value值使用${key名}
typeAliases(类型别名)
Mybatis支持的默认别名
会出现控制台乱码问题<br><typeAliases><br> <!-- <b>批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以)</b> --><br> <b><package name="com.google.domain"/></b><br> <package name="其它包"/><br></typeAliases><br>
乱码
<b><!-- 单个别名定义 不区分大小写--></b><br><typeAliases><br> <typeAlias alias="User" type="com.aaa.domain.User"/><br></typeAliases>
mappers(映射器)
<b>基于XML的自定义mybatis框架</b><br><mapper resource=" " />
使用相对于类路径的资源 如:<mapper resource="com/google/dao/UserDao.xml" />
<b>基于注解方式定义Mybatis框架</b><br><mapper class=" " />
使用mapper接口类路径 如:<mapper class="com.google.dao.UserDao"/> <br>注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<package name=" "/>
注册指定包下的所有mapper接口 如:<package name="com.google.mapper"/> <br><b>注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。</b>
2.mapper配置文件(Dao.xml)
实体类名与数据库名不一致
要配置resultMap对应关系
PageHelper:分页
功能:实现数据库的分页
使用步骤
1.加入maven依赖
<dependency><br> <groupId>com.github.pagehelper</groupId><br> <artifactId>pagehelper</artifactId><br> <version>5.2.1</version><br> </dependency>
2.在mybatis主配置文件加入plugin
<plugins><br> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin><br></plugins>
3.在查询方法前,加入PageHelper方法的调用
PageHelper.startPage(2,5);
0 条评论
下一页