Mybatis总结
之前学过Hibernate,主要的印象就是ORM(对象关系映射),直接操作对象,无需自己书写sql语句,但是这样在关联查询时,效率较低,也不好做sql优化。
现在学习了Mybatis,稍作总结。
一、什么是Mybatis,Mybatis框架原理是什么?
Mybatis也是JDBC操作的封装,属于半ORM框架,是一个持久层的框架,将sql语句写入xml配置文件,通过提供的映射方式,自由灵活的生成满足需要的sql语句。
Mybatis的框架原理
第一步:通过SqlMapConfig.xml,配置了数据源、事务等Mybatis的运行环境
第二步:根据配置文件,创建SqlSessionFactory,使用单例模式,用来创建SqlSession
第三步:SqlSession是一个接口,面向程序员的接口,用来操作数据库的增删改查
第四步:Executor(执行器),是一个接口(基本执行器,缓存执行器),是在SqlSession内部通过执行器操作数据库
第五步:mapped statement(底层封装对象),对操作数据库存储封装,包括sql语句,输入参数类型,输出结果类型。
第六步:mysql上执行操作
二、Mybatis的核心配置文件SqlMapConfig.xml
在sqlMapConfig.xml中的主要配置,其中包括settings标签,environments标签,mappers标签等。
setting配置全局参数,mappers配置mapper.xml映射的引入(单个引入,批量引入)
db.properties的配置文件
三、Mybatis的核心
1、输入映射和输出映射
这块主要是看mapper.xml配置文件
举例,对用户表的操作
用户表如下:
UserMapper.xml配置如下:
这里只是简单的输入映射和输出映射,mapper的namespace对应mapper映射接口(有点类似包的作用),主要的有select标签,insert标签,update标签,delete标签等。
其中,id参数是标识(与mapper接口中的方法名一致),parameterType参数是输入映射,resultType参数是输出映射。
值得注意的是除了resultType(查询到的列名和resultType指定的pojo的属性名一致,才会映射成功),还有resultMap,Mybatis可以使用自定义的resultMap完成高级映射。下面再举例讲。
另外,#{} 表示占位符 ? ,${} 表示拼接符 会导致sql注入 不推荐使用。
2、mapper接口代理开发的方式
这是在配置文件写好之后,再编写对应的mapper接口,需要与mapper.xml配置文件要同名,并放在一个包下
举例,对应UserMapper.xml的UserMapper.java
需要注意的是,UserMapper.java是一个接口,方法名与UserMapper.xml中id对应,方法的参数与parameterType对应,方法的返回值类型与resultType对应。
测试代码如下,sqlSessionFactory使用单例。
3、原生Dao开发(主要还是用Mapper接口代理开发方式)
这部分和之前编写Dao一样,也是Dao接口,然后是DaoImpl类。
举例,对用户表操作
UserDao.java如下
UserDaoImpl.java如下:
这里主要注意的是SqlSession的方法,常用的selectOne(返回单个对象),selectList(返回集合对象),insert,update,delete等
测试代码如下:
4、动态sql语句
这部分也是在Mapper.xml中配置的,通过表达式进行判断,对sql进行灵活拼接,组装。总之,根据不同的需求进行拼装。可以引用自定义的sql片段,不用重复书写同样的sql。
根据需求进行举例。
进行综合查询。在给定的几个id中查询对应性别和模糊查询姓名。
所用到的po类,UserQueryVo类是专门用来测试用的po类,UserCutom类是User类的扩展类(在这里没有扩展什么,相当于一样)
这里是UserMapper.xml中配置的,自定义的sql片段,以及引用sql片段。包括sql标签,if标签,foreach标签
在where标签中,使用include标签根据sql片段的id,引用sql片段。注意where标签可以自动去除拼接条件中第一个and
这里拼接的语句是select * from user where user.sex=? and user.username LIKE '%xxxx%' and ( id=? or id =? or id =?)
测试使用JUnit4。测试代码如下:
综合查询:在给定的id为1,7,12中查询性别为1(男)和姓名中包含wzq的用户。
这里很重要,也很灵活,需要根据不同的需求进行操作。
2018.7.9 明天继续总结
四、高级结果集映射
这里说的高级结果集映射包括一对一,一对多,多对多,其中po类中包含单个po类或者多个po类
首先要学会分析数据库表。首先,按着模块进行查看所需的单个表内记录的内容;然后,查看每个表的重要字段,如非空字段,外键字段;再次,在数据库级别上查看表与表之间的主外键关系;最后,看表与表之间的业务关系。
至于,高级结果集映射的主要配置是在mapper.xml中,根据自定义的resultMap进行映射。
一对一查询,可以使用resultMap,也可以使用resultType。这里举例查询订单,关联查询下订单的用户信息。
订单表和用户表如下:
另外,补充一下order类
UserMapper.xml的配置
首先配置select查询,select标签的resultMap属性是根据resultMap的id来查找的。
使用resultMap的自定义输出映射,需要注意的是resultMap标签中的属性type,id。还有id标签(主键id的配置),result标签(),以及association标签(关联对应的po类,再进行映射配置)。
UserMapper.java中添加对应的方法名
然后就是测试代码
一对多查询,需求是还是查询订单,但关联查询订单详细条目
订单详细条目表如下:
订单详情表对应的pojo类,如下:
首先也是配置mapper.xml,然后在mapper接口中添加对应id的方法名,最后通过测试代码实现。
这里配置自定义的reusltMap时,继承了上面关联用户查询的resultMap,在查询时把用户信息和订单详情都查询出来啦。
1.先上select标签,再就是resultMap标签
值得注意的是order类中有成员变量list,在自定义resultMap中 使用collection标签进行映射
2.在mapper接口中添加对应id的方法名
3.进行测试
多对多查询,查询用户信息和用户所购买的商品信息
先看一下item表和item表对应的pojo类
还是三步走,配置(select,resultMap),接口(添加方法名),测试(实现)。
1.配置如下:
然后配置resultMap
2.mapper接口中添加对应的方法名
3.测试
到这里,一对一,一对多,多对多,都举例完成。
主要是resultType和resultMap的用法,resultMap标签里的association和collection标签用来完成一对一和一对多的映射。
五、延迟加载和查询缓存
1.延迟加载
什么是延迟加载?
延迟加载是先从单表查询,当需要时再从关联表去关联查询。
为什么要延迟加载,延迟加载有什么好处?
延迟加载能大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
如何实现延迟加载?
可以使用association、collection来实现延迟加载的功能。
具体做法,在mapper.xml中自定义的resultMap中的association、collection进行配置。
在mapper.xml配置之前,需要在sqlMapConfig.xml中的settings标签中,开启延迟加载和关闭积极加载。
举例说明,如查询订单,关联查询用户信息。先单表查询订单表,在需要用户信息时,再查询用户表。
首先,在mapp.xml中配置两个select查询,再自定义resultMap进行延迟加载的配置。
然后就是在mapper.java中添加方法。
最后测试
结果如下,并没有一次性关联查询出结果,在需要用户信息时才会去查询用户表。
2.查询缓存
Mybatis提供查询缓存,用于减轻数据压力,提高数据库性能,减少IO操作。
Mybatis提供一级缓存和二级缓存。
一级缓存,是sqlSession级别的缓存,在操作数据库时,需要构造一个sqlSession对象,这个对象里面有一个数据结构(HashMap),用于存储缓存数据。不同sqlSession之间的缓存数据区域是互不影响的。
一级缓存是默认开启的,不需要在配置文件中配置。
二级缓存,是mapper级别的缓存,多个sqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession。
二级缓存是默认开启的,但是除了在sqlMapConfig.xml中有一个总开关外,还需在对应的mapper.xml中开启二级缓存。
在sqlMapConfig.xml的settings标签内配置 <setting name= "cacheEnabled" value="true"/>
在对应的maaper.xml中配置对应的<cache><cache/>
在一级缓存中,当sqlSession查询完毕后,关闭时,Mybatis会清空一级缓存,并会将数据写入二级缓存,当另一个sqlSession查询同样数据时,会从二级缓存中取出。
当sqlSession操作数据库进行数据更改后,提交commit()后,会清空二级缓存对应的数据,当再次查询时,会再次从发送sql从数据库中查询,再存入一级缓存,当sqlSession.close()之后,再写入二级缓存。
二级缓存应用场景,对访问多的查询请求且用户对查询结果实时性要求不高的情况。比如耗时较高的统计分析sql,电话账单sql等。
同时,二级缓存也有局限性,因为二级缓存是mapper级别的,比如商品信息,用户查询的都是最新的商品信息,当商品信息成千上万的在二级缓存中时,只要更新了一个商品信息,就会清空所有的商品信息。解决方法:可以从在业务层根据需求对数据有针对性缓存。
六、逆向工程
Mybatis需要程序员自己书写sql,但是Mybatis也提供逆向工程,针对数据库的单表,自动生成所需的mapper.xml和mapper.java。
运行逆向工程需要三步,第一步下载逆向工程的jar包,第二步配置生成代码的配置文件,第三步书写java生成程序,执行。(当然还有别的方法,请查询官网,常用的是使用java程序)
第一步,jar包
第二步,配置生成代码的配置文件
<generatorConfiguration>
<!-- <classPathEntry location="F:\mybatis-generator-core-1.3.2\lib\mysql-connector-5.1.8.jar" /> -->
<!-- -->
<context id="sysGenerator" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否除去自动生成的注释 true:去除 false:不去除 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!-- 数据库连接信息 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root" password="root">
</jdbcConnection>
<!-- -->
<javaTypeResolver>
<!-- 默认为false JDBC DECIMAL和NUMERIC类型解析为Integer
为true, JDBC DECIMAL和NUMERIC类型解析为BigDecimal -->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成po类的位置 -->
<javaModelGenerator targetPackage="cn.itcast.ssm.po"
targetProject="./src">
<property name="enableSubPackages" value="false" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- mapper映射文件 -->
<sqlMapGenerator targetPackage="cn.itcast.ssm.mapper"
targetProject="./src">
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- mapper接口 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="cn.itcast.ssm.mapper" targetProject="./src">
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!--指定数据库的表 -->
<table tableName="user"></table>
<table tableName="orders"></table>
<table tableName="orderdetail"></table>
<table tableName="items"></table>
</context>
</generatorConfiguration>
第三步,书写java程序生成
import java.io.File;
import java.util.ArrayList;
import java.util.List;
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 Generator {
public void generator() throws Exception{
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("config/generator.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);
}
public static void main(String[] args) throws Exception {
Generator generator = new Generator();
generator.generator();
}
}
逆向工程会使用就行。
回头再总结一下Spring,Springmvc,整合SSM等。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步