目录
在resources目录下配置jdbc.properties,log4j.properties,mybatis-config.xml。
简介:
MyBatis 是基于ORM的持久层框架,是半自动化的ORM实现。它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJO(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
持久化:就是将内存中有用的数据以某种技术保存起来,并且可以再次取出来应用。也就是说,可以将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型。内存中的数据模型可以是任意数据结构或对象模型,存储数据的类型可以是XML,二进制流,关系模型等。
Mybatis项目创建:
创建maven项目,导入mybatis依赖:
<!-- myBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!-- mysql驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- Junit测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
</dependency>
<!--Log4J日志工具 打印运行日志用的!-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.16.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<!--编译的时候同时也把包下面的xml和properties同时编译进去-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
</build>
<build></build>标签可以让编译同时把xml文件一起编译,不加的话target目录下就没有xml的字节码文件,运行就不会成功(java先编译成字节码文件再执行,每次执行其实是执行target下的文件)。普通java项目是out目录。maven每次修改必须重新加载
在resources目录下配置jdbc.properties,log4j.properties,mybatis-config.xml。
jdbc.properties:
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=root
password=123456
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/mybatis.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 HH:mm:ss}][%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
mybatis-config.xml:
初学使用:
<properties resource="">引入外部jdbc配置文件及其相关设置(例如设置默认值)
<settings><setting name="" value=""/></settings>mybatis全局设置例如:logImpl日志设置,字段映射设置(驼峰下划线忽略)等等
<typeAliases><typeAlias></typeAlias>或<packeage name=""</typeAliases>单个实体类别名或整个包下的实体类别名(默认是类名)
<environments default=""><environment id=""><transactionManager type=""/><dataSource type=""></environment></environments>mybatis环境设置
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 配置文件的根元素 -->
<configuration>
<!-- Mybatis可以使用properties标签来引入外部properties配置文件的内容 -->
<properties resource="jdbc.properties"/>
<!-- 设置:定义mybatis的一些全局性设置 -->
<settings>
<!-- 具体的参数名和参数值 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 环境:配置mybatis的环境 -->
<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>
<mappers>
<mapper resource="com/xk/mapper/UserMapper.xml"/>
</mappers>
</configuration>
mybatis-config.xml里的dataSource属性要和jdbc.properties一一对应。
dataSource的type改为druid更好,druid连接池性能好
建立Mapper包
在Mapper包下建立xxMapper接口、xxMapper.xml、impl包,impl包里创建xxMapperImpl实现类。
xxMapper就是之前学习的dao接口,实现类也和之前类似。
实现类:
注意sqlSessFactory.openSession(),参数为true会自动提交事务,默认false
@Override
public List<User> selectAll() {
InputStream inputStream = null;
SqlSessionFactory sqlSessionFactory = null;
SqlSession session = null;
try {
String resource = "mybatis-config.xml"; // 配置文件
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sqlSessionFactory.openSession(); //获取session,openSession默认值是false,改成true才会自动提交事务
//传入UserMapper.xml下对应的id名
List<User> list = session.selectList("com.xx.mapper.UserMapper.selectAll");
return list;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
session.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
重点:xxMapper.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="com.xx.mapper.UserMapper">
<resultMap id="userMap" type="com.xx.entity.User">
<id column="userid" property="userId" jdbcType="INTEGER"/>
<result column="username" property="username" jdbcType="VARCHAR"/>
<result column="birthday" property="birthday" jdbcType="DATE"/>
<result column="sex" property="sex" jdbcType="CHAR"/>
<result column="address" property="address" jdbcType="VARCHAR"/>
</resultMap>
<!--
当数据库和实体类不匹配时
1.可以使SQL的起别名
2.是resultMap
-->
<!--配置 查询结果的列名和实体类的属性名的对应关系-->
<!--
<resultMap id="userMap" type="com.xx.entity.User">
主键字段的对应
Property 实体类中对应的属性名称
Column 数据库中对应的值–>
<id property="userID" column="id"></id>
非主键字段的对应–>
<result property="" column=""></result>
</resultMap>
-->
<!--查询用户所用信息 resultType确认返回值-->
<select id="selectAll" resultMap="userMap">
select * from user;
</select>
<!--添加新用户 parameterType参数类型 -->
<insert id="addUser" parameterType="com.xk.entity.User">
<!--配置插入操作后,获取插入数据的ID
keyProperty 实体类中对应的属性名称
keyColumn 数据库中对应的值
order 什么时候进行这个操作
resultType 返回值类型
-->
insert into user (userid,username,birthday,sex,address) values (#{userId},#{username},#{birthday},#{sex},#{address});
</insert>
<!--更新用户-->
<update id="updateUser" parameterType="com.xk.entity.User">
update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where userid=#{userId};
</update>
<!--根据ID删除用户-->
<delete id="deleteByID" parameterType="integer">
delete from user where userid=#{userId};
</delete>
<!--根据Id查询用户-->
<select id="findById" parameterType="integer" resultType="com.xk.entity.User">
select * from user where userid= #{userId};
</select>
</mapper>
命名空间(namespace)非常重要,对应src下的目录名,即为全限定名。单一个类名为短名(全局唯一下才可使用)。mybatis通过唯一的namespace.id来确定使用的sql语句,后面可在mybatis-config..xml里配置。
简单的mybatis项目就完成了,可以在test下进行代码测试,对应Mapper建包建类测试里面的的方法,需要在方法上加@Test注解
resultMap和resultType
resultType进行输出映射时,只有查询出来的列名和pojo(简单实例对象)中的属性名一致,该列才可以映射成功,即基本类型、List(List中元素的类型)、Map(单条记录:resultType =map,多条记录:Map中value的类型)。
resultMap可以实现将查询结果映射为复杂类型的pojo,常用于多表查询或字段需要转化的场景
mybatis-config.xml属性
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 配置文件的根元素 -->
<configuration>
<!-- Mybatis可以使用properties标签来引入外部properties配置文件的内容-->
<properties></properties>
<!-- 设置:定义mybatis的一些全局性设置 -->
<settings>
<!-- 具体的参数名和参数值 -->
<setting name="" value=""/>
</settings>
<!-- 类型名称:为一些类定义别名 -->
<typeAliases></typeAliases>
<!-- 类型处理器:定义Java类型与数据库中的数据类型之间的转换关系 -->
<typeHandlers></typeHandlers>
<!-- 对象工厂 -->
<objectFactory type=""></objectFactory>
<!-- 插件:mybatis的插件,插件可以修改mybatis的内部运行规则 -->
<plugins>
<plugin interceptor=""></plugin>
</plugins>
<!-- 环境:配置mybatis的环境 -->
<environments default="">
<!-- 环境变量:可以配置多个环境变量,比如使用多数据源时,就需要配置多个环境变量 -->
<environment id="">
<!-- 事务管理器 -->
<transactionManager type=""></transactionManager>
<!-- 数据源 -->
<dataSource type=""></dataSource>
</environment>
</environments>
<!-- 数据库厂商标识 -->
<databaseIdProvider type=""></databaseIdProvider>
<!-- 映射器:指定映射文件或者映射类 -->
<mappers></mappers>
</configuration>
properties
标签用于引入数据源的配置,也就是数据库的相关配置。该标签有两个属性值:resource 和 url,resource属性用于引入类路径下的资源,url用于引入网络路径或磁盘路径下的资源。注意,properties标签一定要放在最前面,否则Mybatis会报错,引用的时候找不到引的外部文件。
settings
这是Mybatis中极为重要的标签,它的属性基本都会对Mybatis的运行时行为产生影响,每一项设置项用setting标签表示,配置项很多。此标签要求在environments标签之前。
typeAliases
别名处理器,作用是给java实体类起一个名字,引用时可以用别名代替全名,别名不区分大小写。
全限定名过长,一般会在这里配置,省略前面的路径。
1.给具体的类起别名例:com.xx.entity.Employee取别名为Employee,那么映射文件内resultType的值就可以只写成Employee。
2.批量取别名:将包下面的所有类都取别名,默认为类名。假如包下有不同路径下的类的名字冲突,那么可以通过@Alias(“name”)注解来解决。
<typeAliases>
<package name="com.xx.entity"/>
</typeAliases>
plugins
插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
environments
Mybatis可以配置多种环境,每种环境由子标签environment决定,有属性default,值表示指定一个环境的标识符,用于切换环境。
environment
Mybatis可以配置多种环境,每种环境由子标签environment决定,有属性default,值表示指定一个环境的标识符,用于切换环境。
transactionManager
Mybatis中有两种事务管理器,分别是JDBC和MANAGED,JDBC表示使用JDBC的方式进行提交、回滚和事务控制,而MANAGED表示使用J2EE的容器来进行事务的控制。
dataSource
数据源,有属性type,表示使用数据源类型。type有三个取值:UNPOOLED:表示不使用连接池技术;POOLED:表示使用连接池技术;JNDI:表示使用JNDI技术。在dataSource标签下使用properties标签使用OGNL表达式(${driver})配置数据库driver、url、username、password。
databaseIdProvider
作用是让Mybatis支持不同公司的数据库,有type属性,作用是得到数据库厂商的标识,Mybatis就能根据数据库厂商标识来执行不同的sql,默认为DB_VENDOR。Mysql的标识为MySQL,Oracle的标识为Oracle,Sql Server的标识为SQL Server等等,一般跟原名一致,“SQL”三个字母要大写。databaseIdProvider有子标签property,表示为数据库标识起别名。
mappers
可以将写好的映射文件注册到全局配置文件当中,每一个mapper子标签标识注册一个sql映射文件。mapper子标签有三个属性,resource标识类路径下的sql映射文件,url标识网络路径或磁盘路径下的映射文件,前两个属性用于注册映射文件,第三个属性class用于注册接口。
注册SQL映射文件(xxMapper.xml)的三种方式:
1.使用resource属性注册,引用类路径下的配置文件xxMapper.xml进行注册
格式:<mapper resource="com/xx/mapper/UserMapper.xml"/>
2.使用class注册接口,使用class注册接口,那么映射文件应当与接口类在同一目录下并且同名。 格式:<mapper class="com.xx.entity.User"/>。class还有另外一个用途,注册那些使用注解来描写sql语句的接口。
3.使用url注册,url是引用网络路径或者磁盘路径下的sql映射文件
4.批量注册,要求SQL映射文件与接口同名并且在同一目录下。
格式:<package name="com.xx.mapper"/>
方式二和方式四都要他的接口和mapper配置文件在同一个包下面,并且要求同名
mybatis设置自增
1.xxMapper.xml的sql标签里添加useGeneratedKeys="true",KeyProperty="自增的字段名"
2.xxMapper.xml的sql语句前添加<selectKey KeyProperty="字段名" resultType="数据类型" Order="AFTER"> SELECT LAST_INSERT_ID()</selectKey>
字段名与属性名不一致的处理
1.sql语句为字段起别名 2.mybatis-config中设置Mybatis的全局配置<typeAliase> 3.使用resultMap
mybatis传入多个参数的方式
1.mybatis处理多个参数时,会把参数存放到map集合里,可以通过存放顺序使用
#{arg0},#{arg1}或#{param1},#{param2}
2.通过@Param("字段名") 注解设置参数名来使用
3.把多个参数传入map集合对象,通过key来使用,和方式一不同的是,这里使用的是参数名: #{字段名}
多表查询
创建数据表结构
数据表结构根据一对一、一对多(多对一)、多对多 三种关系设置外键(一对一或一对多、多对一)或中间表(多对多),实质就是对一或对多。
表的结构不同,对应关系会不同,实体类也会不同,Mapper.xml也会不同
外键:若根据a表查b表,则在a表添加b表的主键做外键
中间表:至少要有两个表主键做字段
建立实体类
根据结构创建实体类。
一对一,多对一:若根据a表查b表,则a实体类里添加b的对象
一对多,多对多:若根据a表查b表,则a实体类里添加b的对象集合
编写Mapper.xml
选择分布查询或级联查询,根据对应关系编写映射sql语句。
association:用于和一个复杂的类型进行关联,即用于一对一或多对一的关联配置。
- property:对应被配置一对一属性对应实体类中的属性名,必填
- javaType:对应被配置一对一属性对应的Java类型
- select:查询标签的id,MyBatis会额外执行这个查询获取嵌套对象的结果
- column:列名,将主查询种的列的结果作为嵌套查询的参数,配置方式如column={prop1=col1,prop2=col2},prop1和pro2将作为嵌套查询的参数
- fetchType:数据加载方式,可选值为 lazy 和 eager,这个配置会覆盖全局的lazyLoadingEnabled配置,一对一默认是eager
collection:用于和一个复杂的集合进行关联,即用于一对多或多对多的关联配置。
- property:是指要操作的集合元素属性
- ofType:指的是集合元素的类型
- column:用于指定集合元素在数据库中对应的列名
- fetchType:数据加载方式,可选值为 lazy 和 eager,这个配置会覆盖全局的lazyLoadingEnabled配置,一对多、多对多默认是lazy
分步查询
优点:
- sql简单,便于理解
- 可以实现延迟加载,延迟加载可以避免在分步查询中执行所有的SQL语句,节省资源,实现按需加载,需要在核心配置文件中添加如下的配置信息
<settings><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/>
</settings>
缺点:会出现"N+1"问题,一个查询语句会导致多个SQL语句执行
sql语句写在不同的Mapper.xml里(查询的表不同,更规范。一个Mapper.xml也可以)
一对一分步查询:
CardMapper.xml里:
<!-- card,person表一对一分步查询-->
<resultMap id="cardPersonMap" type="Card">
<id column="cardId" property="cardId"></id>
<result column="cardDesc" property="cardDesc"></result>
<association property="person" javaType="Person" column="cardId" select="com.xk.mapper.PersonMapper.selectPersonByCardId" fetchType="lazy">
</association>
</resultMap>
<select id="selectCardByIdWithPerson" resultMap="cardPersonMap">
select *
from card
where cardid = #{cardId}
</select>
<!-- personMapper.xml里 card,person表一对一分步查询-->
<select id="selectPersonByCardId" resultType="Person">
select * from person where personId=#{personId}
</select>
多对一分步查询:
<!--tel,person表 多对一分步查询-->
<resultMap id="telPersonMap" type="Tel">
<id column="telId" property="telId"></id>
<result column="telDesc" property="telDesc"></result>
<association property="person" javaType="Person" column="telId" select="com.xk.mapper.PersonMapper.selectPersonByTelId"></association>
</resultMap>
<select id="selectTelByIdWithPerson" resultMap="telPersonMap">
select * from tel where telId=#{telId}
</select>
<!--personMapper.xml里-->
<select id="selectPersonByTelId" resultType="Person">
select * from person where personId=#{personId}
</select>
一对多分步查询:
<!-- tel,person表一对多分布查询-->
<resultMap id="telPersonMap" type="Tel">
<id column="telId" property="telId"></id>
<result column="telDesc" property="telDesc"></result>
<collection property="persons" ofType="Person" column="telId" select="com.xk.mapper.PersonMapper.selectPersonByTelId"></collection>
</resultMap>
<select id="selectTelByIdWithPerson" resultMap="telPersonMap">
select * from tel where telId=#{telId};
</select>
<!--tel,person表一对多分步查询-->
<select id="selectPersonByTelId" resultType="Person">
select * from person where telId=#{telId};
</select>
多对多分步查询:
<!-- knowledge,person表多对多分步查询 -->
<resultMap id="knowledgePersonMap" type="Knowledge">
<id column="knowledgeId" property="knowledgeId"></id>
<result column="knowledgeDesc" property="knowledgeDesc"></result>
<collection property="persons" ofType="Person" column="knowledgeId" select="com.xk.mapper.PersonMapper.selectPersonByKnowledgeId"></collection>
</resultMap>
<select id="selectKnowledgeByIdWithPerson" resultMap="knowledgePersonMap">
select * from knowledge where knowledgeId=#{knowledgeId};
</select>
<!-- personMapper.xml里 -->
<select id="selectPersonByKnowledgeId" resultType="Person">
select * from person p,person_knowledge pk where pk.knowledgeId=#{knowledgeId} and p.personId=pk.personId;
</select>
级联查询
优点:代码集中,获取关联数据十分便捷。
缺点:但是级联过多会增加系统的复杂度,同时降低系统的性能,此增彼减。所以记录超过 3 层时,就不要考虑使用级联了,因为这样会造成多个对象的关联,导致系统的耦合、负载和难以维护。
<!-- social,person表一对一级联查询 -->
<resultMap id="socialPersonMap" type="Social">
<id column="socialId" property="socialId"></id>
<result column="socialDesc" property="socialDesc"></result>
<association property="person" javaType="Person" column="socialId">
<id column="personId" property="personId"></id>
<result column="personDesc" property="personDesc"></result>
</association>
</resultMap>
<select id="selectSocialByIdWithPerson" resultMap="socialPersonMap">
select *
from person p,
social s
where p.personId = s.personId
and s.socialId = #{socialId}
</select>
<!-- work,person表多对一级联查询 -->
<resultMap id="workPersonMap" type="Work">
<id column="workId" property="workId"></id>
<result column="workDesc" property="workDesc"></result>
<association property="person" javaType="Person" column="workId">
<id column="personId" property="personId"></id>
<result column="personDesc" property="personDesc"></result>
</association>
</resultMap>
<select id="selectWorkByIdWithPerson" resultMap="workPersonMap">
select * from work w,person p where w.personId=p.personId and w.workId=#{workId}
</select>
<!-- work,person表一对多级联查询-->
<resultMap id="workPersonMap" type="Work">
<id column="workId" property="workId"></id>
<result column="workDesc" property="workDesc"></result>
<collection property="persons" ofType="Person" column="workId">
<id column="personId" property="personId"></id>
<result column="personDesc" property="personDesc"></result>
</collection>
</resultMap>
<select id="selectWorkByIdWithPerson" resultMap="workPersonMap">
select * from work w,person p where w.workId=p.workId and w.workId=#{workId}
</select>
<!-- team,person表多对多级联查询 -->
<resultMap id="teamPersonMap" type="Team">
<id column="teamId" property="teamId"></id>
<result column="teamDesc" property="teamDesc"></result>
<collection property="persons" ofType="Person" column="teamId">
<id column="personId" property="personId"></id>
<result column="personDesc" property="personDesc"></result>
</collection>
</resultMap>
<select id="selectTeamByIdWithPerson" resultMap="teamPersonMap">
select * from team t,person p,person_team pt where t.teamId=pt.teamId and p.personId=pt.personId and t.teamId=#{teamId}
</select>
动态sql
mybatis的动态sql是一种根据特定的条件来进行动态拼接sql语句,动态 SQL 是 MyBatis 的强大特性之一,基于OGNL表达式解决sql拼接问题。
if语句
格式:<if test="判断语句"> if条件成立要添加的部分</if> 常用:xx !=null
只使用if经常会出问题,常用if+where搭配使用
trim(where,set)
where:
格式:<where> <if test=""></if>...<if test=""></if> and/or 内容</where>
where标签可以自动生成where关键字,并且把内容之前多余的and或者or去掉,当where标签中没有内容时,此时where标签没有任何效果,它不生成where关键字,where标签不能把其中内容后面多余的and去掉。不用考虑 where 和条件之间的and/or了(and/or 要加在内容之前,内容之后的删不了)
set:用在update语句,前置set关键字,删除多余的逗号,逗号不能少。
格式:<set> <if test=""></if> <if test=""></if> </set>
trim:定制where
格式:<trim prefix="where" prefixOverride="AND"></trim>,<trim prefix="set" suffixOverride=","></trim>
prefix前缀、suffix后缀、xxOverride移除的内容,trim很少使用
choose(when,otherwise):
格式:<choose><when test="判断语句">为true时要添加的条件</when>...<otherwise test=""></otherwise></choose>,otherwise是when标签都不成立时的条件。choose里的选择是互斥的,只会执行其中一个,所以and不写也是可以的
foreach
对集合遍历时使用,常用在构建 in条件语句时
collection集合名、item集合元素、open前缀、separator分隔符、close后缀、index索引
格式:<foreach collection="" item="" open="" separator="" close=""> item=#{item}</foreach>
动态sql可以调用方法
//调用成员方法,将String转换为Date类型
<if test="birthdayStart
>= new java.text.SimpleDateFormat('yyyy-MM-dd').parse('2022-02-21')"
> and user_sex = '女' </if>
//调用静态方法,将String转换为Date类型
<if test="@org.kgc.mybatis.entity.User@getDate('2022-02-01')">
sql片段
提取公共部分,简化代码
格式:<sql id=""> 重复使用的sql代码</sql>
需要使用的地方用<include refId=""></include>引入
CDATA语句
在mybatis的映射文件写sql时,很多时候都需要写一些特殊的字符。例如:"<" 字符 “>” 字符 “>=” 字符 “<=” 字符,但是在xml文件中并不能直接写上述列举的字符,否则就会报错。
格式:<![CDATA [sql语句] ]>
模糊查询:
1.concat('%',#{},'%') 2."%"+#{}+"%" 3.<bind name=" " value=" '%'+变量名+'%'"/>
注解开发
mybatis注解会让java代码和sql语句在一个地方,且配置不便,所以实际上使用不多。
@Select、@Insert、@Update、@Delete、()里填入增删改查的sql语句。
@SelectKey 在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题。数据库主键包括自增和非自增,有时候新增一条数据不仅仅知道成功就行了,后边的逻辑可能还需要这个新增的主键,这时候再查询数据库就有点耗时耗力,我们可以采用selectKey来帮助我们获取新增的主键。
@Results和@Result配合使用相当于resultMap。
@Many、@One 对多对一的映射相当于association和collection。
@Select("select * from user u,user_work w,user_social s where u.userId=#{userId} and u.userId = w.userId and s.userId = u.userId")
@Results({
@Result(property = "userId", column = "userId"),
@Result(property = "userName", column = "userName"),
@Result(property = "birthday", column = "birthday"),
@Result(property = "sex", column = "sex"),
@Result(property = "address", column = "address"),
@Result(property = "tels", many = @Many(select = "selectTelsByUserId"), column = "userId"),
@Result(property = "works", many = @Many(resultMap = "userWorkMap")),
@Result(property = "card", one = @One(select = "selectCardByUserId"), column = "userId"),
@Result(property = "social", one = @One(resultMap = "userSocialMap"))
})
public User selectUserWithMany(Integer userId);
<!-- 一对多分步查询-->
@Select("select * from user_tel where userId = #{userId}")
public List<Tel> selectTelsByUserId(Integer userId);
<!-- 一对多关联查询-->
@Select("这个只是语法要求,其实有用的只是resultMap的定义")
@Results(id = "userWorkMap", value = {
@Result(property = "workId", column = "workId"),
@Result(property = "workDesc", column = "workDesc")
})
public Work queryWorkXX();
<!-- 一对一分步查询-->
@Select("select * from user_card where userId = #{userId}")
public Card selectCardByUserId(Integer userId);
<!-- 一对一关联查询-->
@Select("这个只是语法要求,其实有用的只是resultMap的定义")
@Results(id = "userSocialMap", value = {
@Result(property = "socialId", column = "socialId"),
@Result(property = "socialDesc", column = "socialDesc")
})
public Social querySocialXX();
缓存
MyBatis 是一款优秀的持久层框架,它提供了缓存功能把经常访问但是不经常修改的数据存储在缓存内容中,减少与数据库交互,从而提高查询性能,再次查询相同语句时之间从缓存中查询。MyBatis 的缓存分为一级缓存和二级缓存两种类型。一级缓存默认开启并且无法关闭;二级缓存需要手动开启并进行配置。一级缓存的数据存储在SqlSession对象里面,二级缓存的数据存储在SqlSessionFactory对象里面。
一级缓存:
作用范围是 SqlSession 的生命周期,一级缓存只能在同一个 SqlSession 内部共享, 通过SqlSession 内置的HashMap 来实现的(所以查询结果的地址是一样的)。
失效条件:
- 不同sqlSession
- 相同sqlSession但查询条件不同
- 执行两次相同查询中间有增删改操作
- 手动清除缓存
二级缓存:
二级缓存需要一级缓存关闭或提交后生效
配置步骤:
1.mybatis-config.xml 里配置setting或者(springboot在启动类使用@EnableCaching)
<!-- 二级缓存 -->
<setting name="cacheEnabled" value="true"/>
2.在xxMapper.xml开启缓存:<cache/> 属性有size、readOnly(只读,只读的缓存会给所有调用者返回缓存对象的相同实例(实体类也不用序列化), 因此这些对象不能被修改。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。速度上会慢一些,但是更安全,因此默认值是 false)...,或在mapper接口使用注解@CacheNamespace。
3.对应实体类需要实现Serializable 接口。
失效条件:两次查询间有增删改的操作
分页插件
1.导入依赖
<!--分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.3</version>
</dependency>
2.在mybatis-config.xml配置插件
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 数据库方言 -->
<property name="helperDialect" value="mysql"/>
<!-- 为true时,pageSize=0时查询全部 -->
<property name="pageSizeZero" value="true"/>
<!-- 分页参数合理化,如果pageNum<1查询第一页,pageNum>pages查询最后一页 -->
<!-- 3.3.0版本可用,默认为false,禁用后pageNum<1,pageNum>pages返回空数据 -->
<property name="reasonable" value="true"/>
</plugin>
使用时在查询语句上面
@Test
public void testSelectUserById() {
//紧邻着查询语句
PageHelper.startPage(1, 3);//页数,每页显示数据量
List<User> users = um.selectAll();
for (User user : users) {
System.out.println(user);
}
PageInfo<User> up = new PageInfo<>(users, 3);//查询数据集合,导航栏显示页数
System.out.println(up.getNavigatePages());
System.out.println("总共多少页:"+up.getPages());
//遍历输出导航栏显示的页码
int[] navigatepageNums = up.getNavigatepageNums();
for (int i = 0; i < navigatepageNums.length; i++) {
System.out.println(navigatepageNums[i]);
}
}