当前位置: 首页 > news >正文

Java - MyBatis (下)

Mybatis(下)

一、代码优化

1. Mybatis核心代码中的数据库连接所需的这些属性值,可以通过properties文件外部注入
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456
相应变动
<!--  引入外部配置文件  -->
<properties resource="db.properties"> </properties><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments>
2. 与Mapper接口对应的XML文件中CRUD标签中 parameterType 和 resultType 的对应的包名是全名太长,可以起个别名在MyBatisXML中,之后就可以直接使用别名。
起别名
    <!--  起别名  --><typeAliases><typeAlias type="org.example.User" alias="User" /></typeAliases>
对应变化
    <select id="getUserById" resultType="User" parameterType="int">select * from mybatis.userwhere id=#{id}</select><insert id="addUser" parameterType="User">insert into mybatis.user(id,name,pwd)values (#{id},#{name},#{pwd})</insert>
3. 传参方式:
  • 传单个基本类型、传对象、传map

  • 我们的实体类或者数据库中的表,字段或者参数过多时,我们要使用Map进行传参

二、配置解析:

1.MyBatis核心配置文件

properties(属性)
settings(设置)
typeHandlers(类型别名)
objectFactory(对象工厂)
plugins(插件)
environments(环境变量)environment(环境变量)transactionManager(事务管理器)dataSource(数据源)
databaseldProvider(数据库厂商标识)
mappers(映射器)
properties(属性):

关于数据库中的属性配置,可以直接引入外部文件properties文件。

typeHandlers(类型别名):

为Java类型设置一个短的名字,它只和XML配置有关,就是为了减少类完全限定名的冗余。

settings(设置):

这是MyBatis中极为重要的调整设置,会改变MyBatis的运行时行为。

mappers(映射器)

使用class文件绑定注册

  • 接口和它的Mapper配置文件必须同名

  • 接口和它的Mapper配置文件必须在同一个包下

三、生命周期和作用域

生命周期和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder:
  • 一旦SqlSessionFactory被创建了,就不再需要SqlSessionFactoryBuilder了

  • 最佳作用域:局部变量

SqlSessionFactory:
  • 类似于数据库连接池的概念

  • SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个SqlSessionFactory实例。

  • 最佳作用域:应用作用域,最简单的就是使用单例模式或者静态单例模式

SqlSession:
  • 连接到数据库连接池的一个请求

  • 最佳作用域:用完之后赶紧关闭,否则资源被占用

四、解决属性名和字段名不一致的问题

数据库中表的字段名和实体类中的属性名不一致,类型处理器无法映射,找不到。

解决方法:

1.在SQL语句中,给字段名其个别名,为对应的实体类的属性名。
2.其中,使用resultMap结果集映射,替换resultType。

resultMap的设计思想是,对于简单的语句根本不需要配置显示的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。

<mapper namespace="org.example.Mapper"><resultMap id="UserMap" type="User"><result column="pwd" property="password"/></resultMap><select id="getUserList" resultMap="UserMap">select * from mybatis.user</select>
</mapper>

五、日志

日志工厂

如果一个数据库操作出现了异常,我需要排错,日志就是最好的助手。 可以在MyBatis核心配置文件中使用settings配置指定该日志的具体实现。

提供了以下这些工厂的实现类
SLF4J
LOG4J (掌握)
LOG4J2
JDK_LOGGING
COMMONS_LOGGING
STDOUT_LOGGING (掌握)
NO_LOGGING
STDOUT_LOGGING的实现
    <settings>//标准的日志工厂实现<setting name="logImpl" value="STDOUT_LOGGING"/></settings>

LOG4J

简介

什么是LOG4J?
LOG4J是Apache的一个开源项目,通过使用LOG4J,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件。
我们也可以控制每一条日志的输出格式。
通过定义每一条日志信息的级别,我们能够更加细致地控制日志地生成过程。
通过一个配置文件来灵活地进行配置,而不需要修改应用地代码。

LOG4J的实现
1.先导入LOG4J的包
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>
2.在classpath下建立log4j.properties文件
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
3.配置log4J为日志的实现
    <settings><setting name="logImpl" value="LOG4J"/></settings>
4.LOG4J的使用

如果要在输出日志的类中加入相关语句,就要获取相应的对象
导入包,import org.apache.log4j.Logger;
日志对象:Logger logger = Logger.getLogger(test12.class);(当前类的.class)
日志级别:info、debug、error

static Logger logger = Logger.getLogger(test12.class);@Testpublic void log4j(){logger.info("info:进入了log4j");logger.debug("debug:进入了log4j");logger.error("error:log4j");}

六、分页

分页目的:减少数据的处理量

1.使用limit分页
select * from user limit 0,5
2.使用Mybatis实现分页
    <select id="getUserList" resultMap="UserMap">select * from mybatis.user limit 6;</select>
3.使用RowBounds分页(用java代码实现分页)
4.分页插件

七、使用注解开发

使用面向接口编程,根本原因是解耦、可拓展、提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好。
不需要使用写对应Mapper接口的XML文件了,但是仅限于简单的sql语句,复杂的就不行了。

在Mybatis核心配置文件中
<!--  绑定接口  --><mappers><mapper class="org.example.Mapper"/></mappers>
Mapper接口部分
public interface Mapper {//查询全部用户@Select("select * from User")public List<User> getUserList();
}
测试部分不变
@Testpublic void test() {SqlSession sqlSession = Utils.getSqlSession();Mapper mapper = sqlSession.getMapper(Mapper.class);List<User> userList = mapper.getUserList();for (User user : userList) {System.out.println(user);}sqlSession.close();}

八、Mybatis执行流程剖析

Resources获取加载全局配置文件
实例化SqlSessionFactoryBulider构造器
解析配置文件流XMLConfigBuilder
Configuration所有的配置信息
SqlSessionFactory实例化
transactional事务管理器
创建executor执行器
创建SqlSession
实现CRUD
查看是否执行成功(transactional)
提交事务
关闭

九、使用注解CRUD(仅限简单SQL语句)

Mapper接口
public interface Mapper {//查询全部用户@Select("select * from User")public List<User> getUserList();//根据id查询用户@Select("select * from User where id=#{id}")public User getUserById(@Param("id") int idd);//insert一个用户@Insert("insert into User (id,name,pwd) values (#{id},#{name},#{pwd})")public int addUser(User user);//update一个用户@Update("update User set name=#{name},pwd=#{pwd} where id=#{id}")public int updateUser(User user);//delete一个用户@Delete("delete from User where id=#{id}")public int deleteUser(@Param("id") int idd);
}
测试
    @Testpublic void test() {SqlSession sqlSession = Utils.getSqlSession();Mapper mapper = sqlSession.getMapper(Mapper.class);List<User> userList = mapper.getUserList();for (User user : userList) {System.out.println(user);}sqlSession.close();}@Testpublic void test1() {SqlSession sqlSession = Utils.getSqlSession();Mapper mapper = sqlSession.getMapper(Mapper.class);User userById = mapper.getUserById(1);System.out.println(userById);sqlSession.commit();sqlSession.close();}@Testpublic void test2() {SqlSession sqlSession = Utils.getSqlSession();Mapper mapper = sqlSession.getMapper(Mapper.class);int user = mapper.addUser(new User(8, "暗之月", "5345345"));System.out.println(user);sqlSession.close();}@Testpublic void test3() {SqlSession sqlSession = Utils.getSqlSession();Mapper mapper = sqlSession.getMapper(Mapper.class);int user = mapper.updateUser(new User(8, "暗", "12312"));System.out.println(user);sqlSession.commit();sqlSession.close();}@Testpublic void test4() {SqlSession sqlSession = Utils.getSqlSession();Mapper mapper = sqlSession.getMapper(Mapper.class);int user = mapper.deleteUser(8);System.out.println(user);sqlSession.commit();sqlSession.close();}

十、Lombok(偷懒,但是不建议使用)

使用步骤:

1.在IDEA中安装Lombok插件
2.在项目中导入Lombok的jar包
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version><scope>provided</scope>
</dependency>
3. 使用注解

@Data:在类上使用,就可以实现,无参构造(隐式)、get、set、toString。
@AllArgsConstructor:有参构造器
@NoArgsConstructor:无参构造器(显式)
还有其他

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private int id;private String name;private String pwd;}

十一、复杂SQL语句查询

复杂查询环境搭建

  1. 导入jar包,build,写MyBaits工具类,配置MyBatis核心文件(可以用properties配置连接MySQL的信息)

  2. 新建实体类Teacher、Student

  3. 建立对应的Mapper接口

  4. 建立对应的Mapper.XML文件

  5. 在核心配置文件中绑定注册我们的Mapper接口或者文件

  6. 测试查询是否能够成功

多对一处理(多个学生对应一个老师)

按照查询嵌套处理
<select id="getStudents" resultMap="StudentandTeacher">select * from student s</select><resultMap id="StudentandTeacher" type="Student"><result column="id" property="id"/><result column="name" property="name"/><!--    对象使用association    --><association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/><!--    集合使用collection    --><!--        <collection property="" column=""/>--></resultMap><select id="getTeacher" resultType="Teacher">select * from teacher where id=#{tid}</select>
按照结果嵌套处理
<select id="getStudents" resultMap="StudentandTeacher">select s.id sid,s.name sname,t.name tnamefrom student sjoin teacher t on s.tid=t.id;</select><resultMap id="StudentandTeacher" type="Student"><result property="id" column="sid"/><result property="name" column="sname"/><association property="teacher" javaType="Teacher"><result property="name" column="tname"/></association></resultMap>

一对多处理(一个老师拥有多个学生)

按照结果嵌套处理
    <select id="getTeacher" resultMap="TeacherandStudent">select s.id sid,s.name sname,t.name tname,t.id tidfrom student sjoin teacher t on s.tid=t.idwhere t.id=#{tid}</select><resultMap id="TeacherandStudent" type="Teacher"><result property="id" column="t.id"/><result property="name" column="tname"/><collection property="students" ofType="Student"><result property="id" column="sid"/><result property="name" column="sname"/><result property="tid" column="tid"/></collection>
按照查询嵌套处理
    <select id="getTeacher" resultMap="TeacherandStudent">select * from teacher where id=#{tid}</select><resultMap id="TeacherandStudent" type="Teacher"><result property="id" column="id"/><result property="name" column="name"/><collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudent"/></resultMap><select id="getStudent" resultType="Student">select * from student where tid=#{id}</select>

十二、动态SQL

简介

什么是动态SQL
动态SQL就是根据不同的条件生成不同的SQL语句,就是根据不同条件拼接成不同的SQL语句。
MyBatis的强大特性之一便是它的动态SQL。MyBatis提供了可以被任意SQL映射语句中的强大的动态SQL语言。
搭建环境 (上述)
导包、build、工具类、MyBatis核心配置文件、实体类、Mapper接口、对应XML文件

if

<select id="getBolgList" parameterType="map" resultType="Blog">select *from mybatis.blog<where><if test="title!=null">and title=#{title}</if><if test="author!=null">and author=#{author}</if></where>

对应4种情况

select * from mybatis.blog;(当where中的条件都不符合时,这个where自动省略)
select * from mybatis.blog where title=title;
select * from mybatis.blog where author=author;
select * from mybatis.blog where title=title and author=author;

choose (when,otherwise)

<select id="getBolgListChoose" parameterType="map" resultType="blog">select *from mybatis.blog<where><choose><when test="title!=null">title=#{title}</when><when test="author!=null">and author=#{author}</when><otherwise>and views=#{views}</otherwise></choose></where></select>

对应3种情况

select * from mybatis.blog where title=title;
select * from mybatis.blog where author=author; (当title=null时才执行)
select * from mybatis.blog where views=views; (当title=null and author=null 时才执行)

set

set元素会动态前置SET关键字,同时也会删掉无关的逗号

<update id="updateBolg" parameterType="map">update mybatis.blog<set><if test="title!=null">title = #{title},</if><if test="author!=null">author=#{author}</if></set>where id=#{id}</update>

对应3种情况(不能都为null,否则set部分就缺东西,语法错误)

update mybatis.blog set title=title where id=id;
update mybatis.blog set author=author where id=id;
update mybatis.blog set title=title,author=author where id=id;

trim (where,set) 定制格式

<trim prefix="" prefixOverrides="" suffix="" suffixOverrides="">

foreach

通常在构建 in 条件语句的时候使用

    <select id="getBlogIn" resultType="Blog" parameterType="map">select *from mybatis.blog<where>
#             collection:map中存在一个集合映射
#             item:集合中每个元素名称
#             open、separator、close:格式<foreach collection="authors" item="author"open="and (" separator="or" close=")">author=#{author}</foreach></where></select>

SQL片段

有的时候,我们可能会将一些公共功能的部分抽取出来,方便复用。
使用SQL标签抽取公共的部分

<sql id="if-title-author"><if test="title!=null">title=#{title}</if><if test="author!=null">and author=#{author}</if></sql>

在需要使用的地方使用include标签引用

<select id="getBolgList" parameterType="map" resultType="Blog">select *from mybatis.blog<where><include refid="if-title-author"> </include></where></select>
注意事项:

最好基于单表来定义SQL片段,不要存在where标签

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了!!

先在MySQL中写出完整的SQL,再对应的去修改成为我们的动态SQL实现通用即可!!

十三、缓存

简介

什么是缓存?
1.存在内存中的临时数据
2.将用户经常查询的数据放在缓存中,用户去查询数据就不用从磁盘上查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
为什么使用缓存?
减少和数据库的交互次数,较少系统开销,提高系统效率。
什么样的数据能使用缓存?
经常查询并且不经常改变的数据

MyBatis缓存

MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存) 二级缓存需要手动开启和配置,它是基于namespace级别的缓存。
为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

一级缓存

一级缓存也叫本地缓存
与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库。

二级缓存

二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存。
基于namespace级别的缓存,一个名称空间,对应一个二级缓存。

要启用全局的二级缓存,只需要在你的SQL映射文件中(对应的MapperXML文件中)添加一行:

<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
工作机制

一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
如果当前会话关闭了,这个会话对应的一级缓存就没了,但是我们想要的话,会话关闭了,一级缓存中的数据被保存到二级缓存中;
新的会话查询信息,就可以从二级缓存中获取内容。

总结:

只要开启了二级缓存,在同一个Mapper下就有效。
所有的数据都会放在一级缓存中,只有当会话提交或者关闭的时候,才会提交到二级缓存中。
缓存顺序:先看二级缓存中有没有-->再看一级缓存中有没有-->查询数据库

自定义缓存 Ehcache

Ehcache是一种广泛使用的开源Java分布式缓存,是一个Java缓存框架,提供快速、简单的内存和分布式缓存解决方案,主要面向通用缓存。


http://www.mrgr.cn/news/45655.html

相关文章:

  • 探索计算机科学的奥秘:从基础到进阶
  • Vue3 使用 pinia
  • gin如何具体利用Server-Send-Events(SSE)实时推送技术实现消息推送
  • ai助手写作查重率多少?推荐这6款AI论文写作工具
  • 命名管道Linux
  • 2-116 基于matlab的主成分分析(PCA)及累积总和(CUSUM)算法故障监测
  • 计算机网络:数据链路层详解
  • GCC保姆级教程
  • 【Vue】Vue 快速教程
  • UE C++ 实时加载模型的总结
  • 101 公司战略的基本概念
  • 【物流配送中心选址问题】基于改进粒子群算法
  • dotnet7==windows ZIP方式安装和web demo和打包
  • SpringBoot Jar 包加密防止反编译
  • C语言-文件IO
  • 『网络游戏』Tips弹窗队列【10】
  • 头歌实践教学平台 大数据编程 实训答案(二)
  • Python 数据结构与算法全攻略:带你从新手速变高手
  • MARL多智能体强化学习
  • 【微服务】网关 - Gateway(下)(day8)