1.Mybatis的使用
引入依赖
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
1.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>
<properties resource="jdbc.properties"/>
<typeAliases>
<package name="com.wyr.pojo"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.wyr.mapper"/>
</mappers>
</configuration>
2.创建模板文件
2.Mybatis获取参数的两种方式
${} 本质字符串拼接 #{}本质占位符赋值
1.Mybatis获取参数值的各种情况:
1.mapper接口方法的参数为单个字面量类型
可以通过${}和
select * from user where username = '${username}'
或
select * from user where username = #{username}
2.mapper接口方法的参数为多个时
此时Mybatis会将这些参数放在一个map集合中,以两种方式进行存储 a>以arg0,arg1…为键,以参数为值 b>以param1,param2…为键,以参数为值 因此只需要通过#{}或者
以
键
的
方
式
访
问
值
即
可
,
但
是
需
要
注
意
{}以键的方式访问值即可,但是需要注意
以键的方式访问值即可,但是需要注意{}的单引号问题
<!--User getUserLogin(String username,int password);-->
select * from user where username= #{param1} and password =#{param2}
3.mapper接口方法的参数有多个时,可以手动将这些参数放在一个map集合中存储
只要通过#{}和
以
键
(
自
定
义
键
)
的
方
式
访
问
值
即
可
,
但
是
需
要
注
意
{}以键(自定义键)的方式访问值即可,但是需要注意
以键(自定义键)的方式访问值即可,但是需要注意{}的单引号问题
Map<String,Object> map = new HashMap<String,Object>();
map.put("password",123);
map.put("username","www");
<!--User getUserLogin(Map<String,Object> user);-->
<select id="getUserLogin1" resultType="user" parameterType="map">
select * from user where username= #{username} and password =#{password}
</select>
4.mapper接口的参数是实体类类型的参数
只要通过#{}和
以
属
性
的
方
式
访
问
属
性
值
即
可
,
但
是
需
要
注
意
{}以属性的方式访问属性值即可,但是需要注意
以属性的方式访问属性值即可,但是需要注意{}的单引号问题
5.使用@Param注解命名参数(接受多个参数)
此时Mybatis会将这些参数放在一个map集合中,会以两种方式存储 1.以@param注解的值为键,以参数为值 2.以param1,param2…为键,以参数为值 因此只需要通过#{}和
以
键
的
方
式
访
问
值
以
可
,
但
是
需
要
注
意
{}以键的方式访问值以可,但是需要注意
以键的方式访问值以可,但是需要注意{}的单引号问题
属性:有set,get方法的变量
6.mybatis中设置了默认的类型别名
3.mybatis查询功能之方法放回值
1.根据id查询用户信息为一个map集合
<select id="getUserByIdToMap" resultType="map">
select * from user where id= #{id}
</select>
2.查询所有用户信息为一个map集合的方式
<select id="getUsersToMap" resultType="map">
select * from USER ;
</select>
<select id="getUsersToMaps" resultType="map">
select * from user
</select>
4.特殊sql的执行
(1). mybatis处理模糊查询
<select id="getUsersByLikeName" resultType="user">
select * from user where username like '%${username}%'或者
select * from user where username like '%'#{username}'%'
</select>
<select id="getUsersByLikeName" resultType="user">
select * from user where username like concat('%',#{username},'%')
</select>
(2).批量删除(不用)
<delete id="deleteMore" parameterType="string">
delete from user where id in (${ids})
</delete>
(3).mybatis动态设置表名
<select id="getUserByTableName" parameterType="string" resultType="user">
select * from ${tableName}
</select>
(4).添加功能获取自增的主键
<insert id="insertUser" parameterType="User" useGeneratedKeys="true" keyProperty="id">
insert into user values (null,#{username},#{password})
</insert>
5.解决字段名和属性名不一致的情况
- 为字段起别名,保持和类中属性名一致
- mybatis-config.xml全局配置文件中,将数据库字段中_自动映射为驼峰
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
- 通过resultmap实现自定义映射关系(类中属性和表中字段的映射)
(同名的也要写)
<resultMap id="EmpMap" type="emp">
<id property="eno" column="eno"></id>
<result property="eName" column="e_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
</resultMap>
<select id="getAllEmps" resultMap="EmpMap">
select * from t_emp;
</select>
(1)处理多对一的映射关系解决方法
1. 通过级联属性解决多对一的映射关系涉及两个类
<resultMap id="EmpAndDeptOne" type="emp">
<id property="eno" column="eno"></id>
<result property="eName" column="e_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<result property="dept.deptNo" column="dept_no"></result>
<result property="dept.deptName" column="dept_name"></result>
</resultMap>
<select id="getEmpById" resultMap="EmpAndDeptOne" >
select * from t_emp
left join t_dept on t_emp.did= t_dept.dept_no
where t_emp.eno = #{empId}
</select>
2.通过association 解决多对一的映射
<resultMap id="EmpAndDeptTwo" type="emp">
<id property="eno" column="eno"></id>
<result property="eName" column="e_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
<association property="dept" javaType="Dept">
<id property="deptNo" column="dept_no"></id>
<result property="deptName" column="dept_name"></result>
</association>
</resultMap>
<select id="getEmpById" resultMap="EmpAndDeptTwo" >
select * from t_emp
left join t_dept on t_emp.did= t_dept.dept_no
where t_emp.eno = #{empId}
</select>
3.通过分步查询解决多对一的映射关系
<association property="dept"
column="did"
select="com.wyr.mapper.DeptMapper.getDeptById"
fetchType="eager"
>
</association>
</resultMap>
<select id="getEmpAndDeptByStep" parameterType="int" resultMap="empAndDeptByStepResultMap">
select * from t_emp where eno= #{eId}
</select>
<select id="getDeptById" parameterType="int" resultType="Dept">
select * from t_dept where dept_no = #{dId}
</select>
4.延迟加载与(分布查询相关)
与3相关 lazyLoadingEnabled:实现按需加载如果只需要员工姓名则只执行emp的sql语句 如果需要emp中所有属性(包括dept)则是查询emp和dept
(2)处理一对多的映射关系的解决方法
1.通过.collection解决一对多的映射关系
<resultMap id="DeptAndEmpResultMap" type="Dept">
<id column="dept_no" property="deptNo"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps" ofType="Emp">
<id property="eno" column="eno"></id>
<result property="eName" column="e_name"></result>
<result property="age" column="age"></result>
<result property="sex" column="sex"></result>
<result property="email" column="email"></result>
</collection>
</resultMap>
<select id="getDeptAndEmpByDeptId" resultMap="DeptAndEmpResultMap" parameterType="int">
SELECT * FROM t_dept
LEFT JOIN t_emp
ON t_dept.dept_no = t_emp.did
WHERE t_dept.dept_no = #{dId}
</select>
2.通过分布查询解决一对多的映射关系
<resultMap id="deptAndEmpByDeptIdStepResultMap" type="Dept">
<id column="dept_no" property="deptNo"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps"
select="com.wyr.mapper.EmpMapper.getEmpsByDeptId"
column="dept_no"
fetchType="lazy"
>
</collection>
</resultMap>
<select id="getDeptAndEmpByDeptIdStep" resultMap="deptAndEmpByDeptIdStepResultMap" parameterType="int">
select * from t_dept where dept_no = #{dId}
</select>
6.动态sql
本质:一系列标签 功能:帮我们动态拼接sql语句
(1)if
根据标签中test属性所对应的表达式决定标签中的内容是否需要拼接到sql中
<select id="getEmpByCondition" parameterType="Emp" resultType="Emp">
select * from t_emp where 1=1
<if test="eName!=null and eName!=''">
e_name = #{eName}
</if>
<if test="age!=null and age!=''">
and age =#{age}
</if>
<if test="sex!=null and sex!=''">
and sex =#{sex}
</if>
</select>
(2) where
<select id="getEmpByCondition" parameterType="Emp" resultType="Emp">
select * from t_emp
<where>
<if test="eName!=null and eName!=''">
e_name = #{eName}
</if>
<if test="age!=null and age!=''">
and age =#{age}
</if>
<if test="sex!=null and sex!=''">
and sex =#{sex}
</if>
</where>
</select>
(3) trim=where增强
<select id="getEmpByCondition" parameterType="Emp" resultType="Emp">
select * from t_emp
<trim prefix="where" suffixOverrides="and">
<if test="eName!=null and eName!=''">
e_name = #{eName} and
</if>
<if test="age!=null and age!=''">
age =#{age} and
</if>
<if test="sex!=null and sex!=''">
sex =#{sex}
</if>
</trim>
</select>
(4)choose when otherwise 相等于 if elseif’…else
choose 是父标签 if…elseif…elseif=when else=otherwise when至少有一个 otherwise至多一个
<select id="getEmpByCondition" parameterType="Emp" resultType="Emp">
select * from t_emp
<where>
<choose>
<when test="eName!=null and eName!=''">
e_name = #{eName}
</when>
<when test="age!=null and age!=''">
age = #{age}
</when>
<when test="sex!=null and sex!=''">
sex = #{sex}
</when>
<otherwise>
did = 1
</otherwise>
</choose>
</where>
</select>
(5)foreach
- collection:设置需要循环的数组或者集合
- item:标识数组或者集合中的每一个数据
- separator:循环体之间的分隔符
- open:foreach标签所循环的所有内容的开始符
- close:foreach标签所循环的所有内容的结束符
<select id="deleteMoreByArray" parameterType="int">
delete from t_emp where eno in
<foreach collection="eids" item="eid" open="(" close=")" separator=",">
#{eid}
</foreach>
delete from t_emp where
<foreach collection="eids" item="eid" separator="or">
eno = #{eid}
</foreach>
</select>
<insert id="insertMoreByList" parameterType="emp">
insert into t_emp
values
<foreach collection="empList" item="emp" separator=",">
(null,#{emp.eName},#{emp.age},#{emp.sex},#{emp.email},null)
</foreach>
</insert>
(6)sql
<sql id="empColumns">
eno,e_name,sex,age,email
</sql>
select <include refid="empColumns"></include> from t_emp
7.Mybatis的缓存
(1)一级缓存
一级缓存默认是开启的,缓存针对的是查询数据 手动清空缓存:sqlSession.clearCache();
(2)二级缓存
1.二级缓存的相关配置
(3)缓存查询的顺序
(4)整合第三方缓存EHCache
- 引入依赖
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
3. 创建EHCache的配置文件ehcache.xml 名字必须叫ehcache.xml
<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="D:\atguigu\ehcache"/>
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
- 设置二级缓存的类型
在xxxMapper.xml文件中设置二级缓存类型
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
- 加入logback日志
存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。 创建logback的配置文件logback.xml,名字固定,不可改变
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
<logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
</configuration>
属性名 | 是否必须 | 作用 |
---|
maxElementsInMemory | 是 | 在内存中缓存的element的最大数目 | maxElementsOnDisk | 是 | 在磁盘上缓存的element的最大数目,若是0表示无穷大 | eternal | 是 | 设定缓存的elements是否永远不过期。 如果为true,则缓存的数据始终有效, 如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断 | overflowToDisk | 是 | 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上 | timeToIdleSeconds | 否 | 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时, 这些数据便会删除,默认值是0,也就是可闲置时间无穷大 | timeToLiveSeconds | 否 | 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大 | iskSpoolBufferSizeMB | 否 | DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区 | diskPersistent | 否 | 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false | diskExpiryThreadIntervalSeconds | 否 | 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s, 相应的线程会进行一次EhCache中数据的清理工作 | memoryStoreEvictionPolicy | 否 | 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。 默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) |
8.mybatis逆向工程=》自动生成实体类mapper…
- 正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的
- 逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
Java实体类 Mapper接口 Mapper映射文件
(1) 创建逆向工程的步骤之清晰简洁版
1. 添加依赖和插件
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.0</version>
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
2.创建逆向工程的配置文件
- 文件名必须是: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>
<context id="DB2Tables" targetRuntime="MyBatis3Simple">
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/demo"
userId="root"
password="root">
</jdbcConnection>
<javaModelGenerator targetPackage="com.wyr.pojo" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<sqlMapGenerator targetPackage="com.wyr.mapper"
targetProject=".\src\main\resources">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.wyr.mapper" targetProject=".\src\main\java">
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
<table tableName="t_emp" domainObjectName="Emp"/>
<table tableName="t_dept" domainObjectName="Dept"/>
</context>
</generatorConfiguration>
3. 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>
<properties resource="jdbc.properties"/>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
<typeAliases>
<package name="com.wyr.pojo"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.wyr.mapper"/>
</mappers>
</configuration>
4.运行程序生成对应文件
(2)复杂版本的使用
与简洁版相似 只需要将创建逆向工程的配置文件中 targetRuntime="MyBatis3Simple"改为 targetRuntime="MyBatis3"即可
相比较简洁版简单的增删查改,复杂版提供了更多的功能
1.QBC
- 查
- selectByExample:按条件查询,需要传入一个example对象或者null;如果传入一个null,则表示没有条件,也就是查询所有数据
- example.createCriteria().xxx:创建条件对象,通过andXXX方法为SQL添加查询添加,每个条件之间是and关系
- example.or().xxx:将之前添加的条件通过or拼接其他条件
@Test
public void test(){
try {
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> emps1 = empMapper.selectByExample(null);
System.out.println(emps1);
EmpExample empExample = new EmpExample();
empExample.createCriteria().andENameEqualTo("张三").andAgeGreaterThanOrEqualTo(20);
empExample.or().andDidIsNotNull();
List<Emp> emps2 = empMapper.selectByExample(empExample);
System.out.println(emps2);
} catch (IOException e) {
e.printStackTrace();
}
}
2.修改 (1).updateByPrimaryKey:通过主键进行数据修改,如果某一个值为null,也会将对应的字段改为null
empMapper.updateByPrimaryKey(new Emp(1,"wy",null,null,null,null));
(2).updateByPrimaryKeySelective():通过主键进行选择性数据修改,如果某个值为null,则不修改这个字段
empMapper.updateByPrimaryKeySelective(new Emp(3,"wyt",null,null,null,null));
9.分页插件
1.添加依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
2.在MyBatis的核心配置文件(mybatis-config.xml)中配置插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3.使用插件的分页功能
使用MyBatis的分页插件实现分页功能:
1、需要在查询功能之前开启分页 PageHelper.startPage(int pageNum,int pagesize); 2、在查询功能之后获取分页相关信息 PageInfo page = new PageInfo<>(List, 5); List表示分页数据 5标识当前分页的个数
(1)方式一(使用page)
代码:
@Test
public void test(){
try {
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Page<Emp> page = PageHelper.startPage(1, 3);
List<Emp> empList = empMapper.selectByExample(null);
System.out.println(page);
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果:
(2)方式二:使用pageInfo(关于分页的信息更加详细)
@Test
public void test(){
try {
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
SqlSession sqlSession = sqlSessionFactory.openSession(true);
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
PageHelper.startPage(1, 3);
List<Emp> empList = empMapper.selectByExample(null);
PageInfo<Emp> pageInfo = new PageInfo<>(empList,5);
System.out.println(pageInfo);
} catch (IOException e) {
e.printStackTrace();
}
}
结果
(3)1和2结果数据含义
pageNum:当前页的页码 pageSize:每页显示的条数 size:当前页显示的真实条数 total:总记录数 pages:总页数 prePage:上一页的页码 nextPage:下一页的页码 isFirstPage/isLastPage:是否为第一页/最后一页 hasPreviousPage/hasNextPage:是否存在上一页/下一页 navigatePages:导航分页的页码数 navigatepageNums:导航分页的页码,[1,2,3,4,5]
|