Maven项目导入mybatis步骤
0.Mybatis简介和功能
MyBatis 是一款优秀的持久层框架。
MyBatis 避免了几乎所有的 JDBC 代码手动设置参数以及手动获取结果集的操
作。
Mybatis 将基本的 JDBC 常用接口封装,对外提供操作即可.
1.创建表和表对应的实体类
必须为属性生成get和set方法
public class Admin {
private Integer id;
private String account;
private String password;
private String gender;
private String adminAge;
private String opertime;
}
2.导入mybatis和mysql的驱动包
<dependencies>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<!-- mybatis驱动 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
</dependencies>
3.在resources包下添加全局配置文件( mybatis.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>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/> <!--开启日志 -->
<setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 对象映射 下划线和驼峰命名 转化 -->
</settings>
<!-- 为类型配置别名 -->
<typeAliases>
<!-- 为单个类配置别名 -->
<!-- <typeAlias type="com.ffyc.mybatis.model.Admin" alias="admin"></typeAlias> -->
<package name="com.mybatis.model"/> <!-- 导入包中所有实体 -->
</typeAliases>
<!--数据库连接池-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/库名?serverTimezone=Asia/Shanghai" />
<property name="username" value="root" />
<property name="password" value="root"/>
<property name="poolMaximumActiveConnections" value="20"/>
</dataSource>
</environment>
</environments>
<!--配置sql映射文件-->
<mappers>
<mapper resource="mappers/AdminMapper.xml"></mapper>
</mappers>
</configuration>
4.创建对应接口的映射文件
<?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.mybatis.dao.AdminDao"> <!--接口地址-->
</mapper>
5.定义接口
在接口中定义方法
public interface AdminDao{
Admin findAdminById(Integer id);
}
6. 测试Mybatis是否导入
读取配置文件
Reader reader = Resources.getResourceAsReader("mybatis.xml")
创建SqlSessionFactory
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
创建 SqlSession
SqlSession sqlSession = sessionFactory.openSession()
获取接口的代理对象
AdminDao adminDao=sqlSession.getMapper(AdminDao.class);
根据代理对象调用方法
Admin admin=adminDao.findAdminById(1);
如果会对表进行修改,则需要提交事务
sqlSession.commit();
关闭 SqlSession
sqlSession.close();
Mybatis内容点
传入参数
单个参数 直接在sql使用 #{} (占位符)
Admin findAdminById(Integer id);
多个不同参数 使用@Param("sql中使用的名字")
Admin findAdminByAccountPass(@Param("acc") String account,@Param("pass") String password);
传入复杂的对象
利用parameterType="对象的路径.对象"
返回结果
<select id="唯一标识" resultType="int">
select * from admin where id= #{id}
</select>
对象映射
驼峰命名和下划线自动转化
在返回结果为实体类时 resultType=“com.mybatis.model.Admin”
数据库中列名使用下划线连接命名admin_age java实体对象属性名用驼峰命名法adminAge,需配置对象映射使得能相互转化
配置方法:在配置文件中
resultMap
实体类:
public class Student {
private Integer id;
private String name;
private String gender;
private Major major;
}
public class Major {
private Integer id;
private String name;
private List<Student> students;
}
方法一:sql联结后 对属性进行映射
方法一:对要查询的内部类配置映射,sql全部查询:
<resultMap id="studentMap" type="Student"> <!--属性property column数据库中的列 -->
<id column="sid" property="id"></id>
<result column="sname" property="name"></result>
<result column="gender" property="gender"></result>
<association property="major" javaType="Major"> <!-- javaType该成员类的类型 -->
<id column="mid" property="id"></id>
<result column="mname" property="name"></result>
</association>
</resultMap>
<select id="findStudentById" resultMap="studentMap">
select m.id mid,s.id sid,s.name sname,s.gender,m.name mname
from student s left join major m on s.majorid=m.id where s.id=#{id}
</select>
在配置文件中可设置是否自动映射:
<!-- 设置自动映射级别 NONE 完全关闭自动映射 PARTIAL当查询没有嵌套时,自动映射 FULL 必然自动映射 -->
<settings>
<setting name="autoMappingBehavior" value="PARTIAL"/>
</settings>
方法二:使用单表sql查询利用resultMap连接
方法二:将多表查询修改为单表查询 (sql中不需要联结,分两步查询)
<!-- 外层类型 -->
<resultMap id="studentMap1" type="Student">
<!-- 外部类查询属性名 要查的类型 将要执行 传入目标行 -->
<association property="major" javaType="Major" select="findMajorById" column="majorid"></association>
</resultMap>
<!-- 执行此步利用resultMap 查学生信息和班级编号 -->
<select id="findStudentById1" parameterType="integer" resultMap="studentMap1">
select s.id,s.name,gender,majorid
from student s where id=#{id}
</select>
<!-- 班级信息-->
<select id="findMajorById" parameterType="integer" resultType="Major">
select id,name from major where id=#{id}
</select>
一对多查询
问题:查询班级和班级的全部学生
重点: association在一对一使用 collection则是一对多 其中javaType为外部属性类型 一对多会多出 ofType 来确定具体类型
方法一:使用SQL的联结查询后,配置每列映射
方法二: 分开查询
上面介绍为一对一类型
<resultMap id="MajorMap1" type="Major">
<id column="id" property="id"></id>
<!-- 外部成员属性名 成员类型 将要查询类型 传入第二查询语句的列 -->
<collection property="students" javaType="list" ofType="Student" select="findStudentByMajorid" column="id"></collection>
</resultMap>
<!-- 查询班级信息-->
<select id="findMajorById" parameterType="integer" resultMap="MajorMap1">
select id,name from major where id=#{id}
</select>
<!-- 根据班级id查学生 -->
<select id="findStudentByMajorid" parameterType="integer" resultType="student">
select s.id,s.name,gender,majorid
from student s where majorid=#{id}
</select>
返回插入行的信息
使用场景:插入管理员信息找到该行主键对应的位置,一条sql完成不需要再查询
<insert id="addAdmin" parameterType="com.mybatis.model.Admin" useGeneratedKeys="true 开启将keyColumn赋值给keyProperty" keyProperty="Admin中的某个成员" keyColumn="数据库的列">
INSERT INTO admin(account,PASSWORD)VALUES(#{account},#{password})
</insert>
占位符#{}和${}
#{}: 经过预编译,先编译好sql再取值
${}:直接以字符串形式拼接到sql中,例如在 order by ${column} 语句后面可以动态替换列
Mybatis动态SQL
if元素
如果没有 1=1 就会存在两个问题
1.如果条件不为空语句前的and会导致SQL报错
2.两个条件都为空即没有条件全部查询,则会使SQL多出一个where导致SQL报错
<select id="findStudents" parameterType="Student" resultType="Student">
select s.id,s.name,gender,majorid
from student s where 1=1
<if test="id!=null">and id=#{id} </if>
<if test="name!=null">and name=#{name} </if>
</select>
where元素
如果查询条件的个数不确定时 可以用where配合if ,where有两个功能
1.判断是否有返回值,有的话会在SQL中插入where来执行后面的条件查询,没有则不会
2.如果中间开头为and或or,则会自动去除。
这样就算两个条件都为空
<select id="findStudents" parameterType="Student" resultType="Student">
select s.id,s.name,gender,majorid
from student s
<where>
<if test="id!=null">and id=#{id} </if>
<if test="name!=null">and name=#{name} </if>
</where>
</select>
trim元素
trim 是where的升级版,
<select id="findStudents" parameterType="Student" resultType="Student">
select s.id,s.name,gender,majorid
from student s
<!-- 可覆盖前缀 前缀 -->
<trim prefixOverrides="and|or" prefix="where">
<!--integer 默认为空-->
<if test="id!=null">and id=#{id} </if>
<if test="name!=null">and name=#{name} </if>
</trim>
</select>
choose元素
choose类似于if(){} else{} , when标签会按顺序判断是否都满足,如果有一个满足直接跳出执行其中语句,如果都不满足则会执行otherwise。
<select id="findStudents" parameterType="Student" resultType="Student">
select s.id,s.name,gender,majorid
from student s
<where>
<choose>
<when test="id!=null"> id=#{id}</when>
<when test="name!=null"> name=#{name}</when>
<otherwise>id=15</otherwise>
</choose>
</where>
</select>
set元素
在修改时使用,也可以使用trim替代
set版:
<update id="setIds" parameterType="Student">
update admin
<set>
<if test="name!=null">name=#{name}</if>
<if test="phone!=null">phone=#{phone}</if>
</set>
<where>
id=#{id}
</where>
</update>
trim版:
<update id="setIds" parameterType="Student">
update admin
<!-- 后缀 后缀覆盖 -->
<trim suffix="where" prefix="set" suffixOverrides=",">
<if test="name!=null">name=#{name},</if>
<if test="phone!=null">phone=#{phone},</if>
</trim>
id=#{id}
</update>
foreach元素
循环输出数组中的内容到SQL中,在前端勾选查询项后,传要操作的id数组到后端,直接拿数组查询
public interface StudentDao {
List<Major> findMajorById(List<Integer> id);
}
<select id="findMajorById" parameterType="integer" resultType="Major">
select id,name from major where id in
<!-- list集合\array数组 内容 左边界 右边界 分隔符 -->
<foreach collection="list" item="item" open="(" close=")" separator=",">#{item}</foreach>
</select>
特殊符号处理
方法一:转义字符
< <
> >
" "
’ '
& &
方法二:<![CDATA[ ]]>
<select id="findStudents" parameterType="Student" resultType="Student">
select s.id,s.name,gender,majorid
from student s where <![CDATA[id < 10]]>
</select>
模糊匹配问题
第一种: 通过字符串直接拼接,该方法仅支持 不进行预编译的 ${} 占位符
select s.id,s.name,gender,majorid
from student s
where name like '${name}%'
第二种:通过数据库函数拼接,可以通过预编译
select s.id,s.name,gender,majorid
from student s
where name like concat(#{name},'%')
mybatis 一级缓存二级缓存
缓存概念:由于对数据库访问需要读取硬盘,为了减轻数据库的访问压力,将第一次查询的结果保存在java对象中不销毁,以后访问直接从内存中获取不需要访问数据库。
一级缓存
一级缓存是SqlSession级别的
在同一个SqlSession中,再次查询相同内容,会从一级缓存中查询,不会查数据库
并且如果进行增删改操作,就会清空这个SqlSession的所有缓存
强制清除一级缓存的方法
sqlSession.clearCache();
二级缓存
二级缓存是SqlSessionFactory级别,(SqlSessionFactory对象只有一个,被多个SqlSession共用)
使用需要配置
sqlSession.close();
第一步:二级缓存在SqlSession关闭时会把缓存导入SqlSessionFactory缓存区,在执行SQL前会先在缓存区查询是否有缓存,所以与SqlSession的创建时间无关
全局配置文件 (总开关)
<setting name="cacheEnabled" value="true"/>
第二步:Mapper.xml文件(给每个Mapper选择是否开启)
<!-- LRU最少使用 FIFO先进先出 SOFT软引用 WEAK弱引用 -->
<!-- 刷新时间(毫秒级) 缓存对象数量 清除策略 LRU FIFO SOFT WEAK 是否只读 -->
<cache flushInterval="1000" size="" eviction="" readOnly="true"></cache>