文章目录
一、概念
1.1、概念
- MyBatis是一个优秀的基于Java的持久层框架,支持自定义SQL,存储过程和高级反射
- MyBatis对原有的JDBC进行了封装,几乎消除了所有的JDBC代码,使用者只需关注SQL本身
- MyBatis可以使用简单的XML或Annotation来配置执行SQL,并自动完成ORM操作,将执行结果返回
依赖网站:https://mvnrepository.com/
二、步骤
1、Maven项目配置MyBatis
1.导入依赖
<dependencies>
<!--MyBatis核心依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
2.创建mybatis-config.xml配置文件,配置数据库信息
<?xml version="1.0" encoding="UTF-8"?>
<!--mybatis配置文件头,特点为首尾的“configuration”和“mybatis-3-config.dtd”-->
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--核心配置信息-->
<environments default="shine_config">
<!--数据库相关配置-->
<environment id="shine_config">
<!--事务控制类型-->
<transactionManager type="JDBC"></transactionManager>
<!--数据库连接参数-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
<!--&转义&-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis_shine?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=UTF-8"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</dataSource>
</environment>
</environments>
</configuration>
2、开发步骤
已经完成MyBatis配置步骤
1.根据数据表编写User实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
private Boolean gender;
private Date regist_time;
}
2.编写UserDao接口
public interface UserDao {
User queryUserById(Integer id);
}
3.在resource目录下编写UserDaoMapper.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!--mybatismapper文件头,特点为首尾的“mapper”和“mybatis-3-mapper.dtd”-->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.UserDao">
<!--描述方法-->
<!--id为方法名,resultType为返回值类型,arg0表示参数的第一个值-->
<!--queryUserById是Dao中的方法名-->
<select id="queryUserById" resultType="entity.User">
select id,username,password,gender,regist_time
from t_user
where id=#{arg0}
</select>
</mapper>
4.在mybatis-config.xml配置文件中注册mapper文件
<!--注册mapper文件-->
<mappers>
<mapper resource="UserDaoMapper.xml"/>
</mappers>
5.编写测试类TestMybatis.java
public class TestMybatis {
public static void main(String[] args) throws IOException {
//mybatis API
//1.加载配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//2.构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过sqlSessionFactory创建sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.通过sqlSession获得DAO实现类的对象
UserDao mapper = sqlSession.getMapper(UserDao.class);
//5.测试查询方法
User user1 = mapper.queryUserById(1);
User user2 = mapper.queryUserById(2);
System.out.println(user1);
System.out.println(user2);
sqlSession.close()
}
}
2.1一些问题
如果mapper不在常规目录(resource)下
<!--========在pom.xml文件中更改默认编译规则==========================================================-->
<build>
<!--更改Maven编译规则-->
<resources>
<resource>
<!--资源目录-->
<directory>src/main/java</directory>
<!--扫描资源目录下的所有xml文件-->
<includes>
<include>*.xml</include> <!--默认(新添加自定义则失效)-->
<include>**/*.xml</include><!--新添加 */代表1级目录 **/代表多级目录-->
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
<!--========mybatis配置文件中注册mapper文件的路径====================================================-->
<mappers>
<mapper resource="dao/UserDaoMapper.xml"/>
</mappers>
频繁更改环境的问题
<!--
1.在resource目录下创建jdbc-properties文件,并将mybatis配置文件中的url,driver,username,password内容复制到文件相应位置中
-->
jdbc.url = jdbc:mysql://localhost:3306/mybatis_shine?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=UTF-8
jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.username = root
jdbc.password = 123456
<!--
2.在mybatis配置文件中导入jdbc-properties文件
-->
<properties resource="jdbc-properties"></properties>
<!--
3.将mybatis配置文件的数据库连接参数更改为动态参数
-->
<dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
<property name="driver" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
<!--往后更改数据库连接信息只需在jdbc-properties文件中修改即可-->
类别名问题
<!--
方法1,设置某个类的别名,mapper文件中要以这个类为返回对象时,可直接使用设置的别名
-->
<!--在mybatis配置文件中设置实体类别名映射-->
<typeAliases>
<typeAlias type="entity.User" alias="user_shine"/>
</typeAliases>
<!--在对应mapper文件中使用别名-->
<select id="queryUserById" resultType="user_shine">
select id,username,password,gender,regist_time
from t_user
where id=#{arg0}
</select>
<!--
方法2,定义实体类所在的包,每个实体类自动注册一个别名(也就是类名);
mapper文件中要以这个类为返回对象时,可直接写类名
-->
<!--在mybatis配置文件中设置实体类别名映射-->
<typeAliases>
<package name="entity"/>
</typeAliases>
<!--在对应mapper文件中使用别名-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
where id=#{arg0}
</select
日志问题
# 在resource目录下创建log4j.properties文件(固定名字)
# 运行项目就会输出日志
log4j.rootLogger=DEBUG, stdout
log4j.logger.org.mybatis.example.BlogMapper=TRACE
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
三、CURD操作
3.1 查询操作参数绑定的几种方式
方式一
<!--dao接口-->
User queryUserByIdAndUsername(Integer id,String username);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--arg0和agr1和param2表示数据的第一个值和第二个值-->
where id=#{arg0} and username=#{agr1}
</select>
方式二
<!--dao接口-->
User queryUserByIdAndUsername(Integer id,String username);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--param1和param2表示数据的第一个值和第二个值-->
where id=#{param1} and username=#{param2}
</select>
方式三
<!--dao接口-->
User queryUserByIdAndPassword(@Param("id") Integer id,@Param("password") String password);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--此处的id和password是@Param注解定义的名字-->
where id=#{id} and username=#{password}
</select>
方式四
<!--dao接口-->
User queryUserByIdAndPassword2(Map map);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--此处的id和password是Map的key-->
where id=#{id} and username=#{password}
</select>
<!--测试操作-->
Map map = New HashMap();
map.put("id",2);
map.put("password","456");
方式五
<!--dao接口-->
User queryUserByIdAndPassword3(User user);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--此处的id和password是User类中定义的属性名-->
where id=#{id} and username=#{password}
</select>
<!--测试操作-->
User user = new User();
user.setId(1);
user.setPassword("123")
3.2 模糊查询
模糊查询将可能返回多个对象,使用 list<>
使用concat(’%’,#{keyword},’%’)做字符串拼接
<!--dao接口-->
List<User> queryUserByUsername(@Param("username") String username);
<!--mapper文件-->
<select id="queryUserById" resultType="User">
select id,username,password,gender,regist_time
from t_user
<!--concat做字符串拼接-->
where username like concat('%',#{username},'%')
</select>
3.3 delete操作
<!--dao接口-->
void deleteUser(@Param("id") Integer id);
<!--mapper文件-->
<delete id="deleteUser" parameterType="int">
delete form t_user
where id = #{id}
</delete>
<!--
完成操作后,需要调用commit()方法,将操作持久化到数据库,sqlSession.close()释放资源
-->
3.4 update操作
<!--dao接口-->
void updateUser(User user);
<!--mapper文件-->
<update id="updateUser" parameterType="User">
update t_user
set username=#{username},password=#{password},gender={gender},regist_time=#{regist_time}
where id=#{id}
</update>
<!--
完成操作后,需要调用commit()方法,将操作持久化到数据库,sqlSession.close()释放资源
-->
3.5 insert操作
<!--dao接口-->
void insertUser(User user);
<!--mapper文件-->
<insert id="insertUser" parameterType="User">
insert into t_user values(#{id},#{username},#{password},#{gender},#{regist_time})
</insert>
<!--
完成操作后,需要调用commit()方法,将操作持久化到数据库,sqlSession.close()释放资源
-->
3.6 主键回填
当添加数据时,有可能有需要这条添加数据的id,这时候需要用到主键回填
第一种情况,主键是可自增的整型(获取到自增的主键值)
<!--dao接口-->
void insertUser(User user);
<!--mapper文件-->
<insert id="insertUser" parameterType="User">
<!--主键回填,将新数据的ID存入java对象的主键对应的属性中-->
<!--order指定执行顺序,这里的id指的是插入操作中的id参数-->
<selectKey order="AFTER" resultType="int" keyProperty="id">
select last_insert_id()
</selectKey>
insert into t_user values(#{id},#{username},#{password},#{gender},#{regist_time})
</insert>
<!--测试操作-->
User new_ser = new User(null, "shine_652", "00000", true, new Date());
mapper.insertUser(new_ser);
System.out.println(new_ser);<!--查看回填的id-->
sqlSession.commit();
sqlSession.close()
第二种情况,主键是字符串(随机生成UUID存入数据库)
<!--dao接口-->
Integer insertStudent(Student student);
<!--mapper文件-->
<insert id="insertStudent" parameterType="Student">
<!--将主键设置为32位,mysql生成唯一的32位UUID,回填到参数id中-->
<!--使用mysql的replace方法去除生成UUID的短很细和空格-->
<selectKey order="BEFORE" resultType="String" keyProperty="id">
select replace(uuid(),'-','');
</selectKey>
insert into t_student values (#{id},#{name},#{gender});
</insert>
<!--测试操作-->
StudentDao mapper = sqlSession.getMapper(StudentDao.class);
Student student = new Student(null, "shine001", true);
mapper.insertStudent(student);
System.out.println(student);
sqlSession.commit();
sqlSession.close()
四、MyBatis工具类
4.1 封装工具类
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* 1.加载配置
* 2.创建SqlSessionFactory
* 3.创建Session
* 4.事务管理
* 5.mapper获取
*/
public class MyBatisUtil {
private static SqlSessionFactory sqlSessionFactory;
//创建ThreadLocal绑定当前线程中的SqlSession对象
private static final ThreadLocal<SqlSession> tl = new ThreadLocal<SqlSession>();
static { //加载配置信息
//1.加载配置文件
try{
//1.加载配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//2.构建SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (IOException e){
e.printStackTrace();
}
}
//创建sqlSession
public static SqlSession openSession(){
SqlSession sqlSession = tl.get();
if (sqlSession == null) {
sqlSession = sqlSessionFactory.openSession();
tl.set(sqlSession);
}
return sqlSession;
}
//释放资源
public static void closeSession(){
SqlSession sqlSession = tl.get();
sqlSession.close();
}
//提交事务
public static void commit(){
SqlSession sqlSession = openSession();
sqlSession.commit();
closeSession();
}
//事务回滚
public static void rollback(){
SqlSession sqlSession = openSession();
sqlSession.rollback();
closeSession();
}
//mapper获取
public static <T> T getMapper(Class<T> mapper){
SqlSession sqlSession = openSession();
return sqlSession.getMapper(mapper);
}
}
4.2 测试工具类
StudentDao studentMapper = MyBatisUtil.getMapper(StudentDao.class);
Student student = new Student(null, "test_util", true);
studentMapper.insertStudent(student);
MyBatisUtil.commit();
五、映射
5.1 resultMap结果地图
当数据表数据表列名与实体类属性名不一致时
- 在SQL语句中为列名设置别名(与实体类属性名一致)
- 使用resultMap结果地图
<!--定义复杂情况的,映射规则-->
<resultMap id="user_resultMap" type="User">
<!--主键列,column表示数据表的列名,property表示实体类的属性名-->
<id column="id" property="id"/>
<!--普通列,column表示数据表的列名,property表示实体类的属性名-->
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="gender" property="gender"/>
<!--表列名为registTime,因为是在SQL语句中定义的别名-->
<result column="registTime" property="regist_time"/>
</resultMap>
<select id="queryUserById" resultMap="user_resultMap">
select id,username,password,gender,regist_time registTime
from t_user
where id=#{arg0}
</select>
六、关联查询
6.1 一对一
一对一关系,两个表中,主表中的一个字段对应从表中的一条数据
一对一查询注意点:
有以下两张表 (性别列用整型,0和1)

主键和外键列的值相同,只在主表实体类中写就行了
创建表对应的实体类时,添加另一张表的实类类对象(关系属性)
例如:在
Passenger
实体类中添加private Passport passport
在
Passport
实体类中添加private Passenger passenger
PassengerDaoMapper.xml映射文件如下:
一对一的resultMap中使用的是
association
<mapper namespace="dao.PassengerDao">
<resultMap id="passenger_passport" type="Passenger">
<id column="id" property="id"></id>
<result column="name" property="name"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<!--passport指的是Passenger实体类中的Passport对象属性名-->
<association property="passport" javaType="entity.Passport">
<!--此处的表列名为passId,是在SQL语句中取的别名-->
<id column="passId" property="id"></id>
<result column="nationality" property="nationality"/>
<result column="expire" property="expire"/>
</association>
</resultMap>
<!--查询旅客和护照信息-->
<select id="queryPassengerById" resultMap="passenger_passport">
select t_passengers.id,t_passengers.name,t_passengers.sex,t_passengers.birthday,
t_passports.id passId,t_passports.nationality,t_passports.expire
from t_passengers join t_passports
on t_passengers.id = t_passports.passengers_id
where t_passengers.id = #{id}
</select>
</mapper>
6.2 一对多
一对多的关系,两张数据表中,主表中的一个字段对应从表中的多条数据
有以下两张表

主键和外键列的值相同,只在主表实体类中写就行了
创建表对应的实体类时,添加另一张表的实类类对象(关系属性)
例如:主表实体类中的从表实体类对象:
private List<Employee> employee
从表实体类中的主表实体类对象:
private Department department
PassengerDaoMapper.xml映射文件如下:
一对多的resultMap中使用的是
collection
<mapper namespace="dao.DepartmentDao">
<resultMap id="department_result" type="Department">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="location" property="location"></result>
<!--employee是主表实体类中的对象属性名-->
<collection property="employee" ofType="Employee" >
<!--列名为SQL别名-->
<id column="emp_id" property="id"></id>
<result column="emp_name" property="name"></result>
<result column="salary" property="salary"></result>
</collection>
</resultMap>
<select id="queryDepartmentById" resultMap="department_result">
select t_departments.id,t_departments.name,t_departments.location,
t_employees.id emp_id,t_employees.name emp_name,t_employees.salary
from t_departments join t_employees
on t_departments.id = t_employees.dept_id
where t_departments.id=#{id}
</select>
</mapper>
6.3 多对多
多对多关系,至少三张表,一张表为中间表连接另外两张表;从中间表角度看,多对多是复杂化的一对多
有如下三张表,第三张表为中间表,两个字段都是外键

创建表对应的实体类时,添加其他表的实类类对象,中间表不用创实体类(关系属性)
例如:在表1中添加表2的实体类对象:
private List<Subject> subject
在表2中添加表1的实体类对象:
private List<Student2> students
PassengerDaoMapper.xml映射文件如下:
多对多的resultMap中使用的是
collection
<!--课程关联学生查询-->
<mapper namespace="dao.SubjectDao">
<resultMap id="subject_result" type="Subject">
<id column="id" property="id"></id>
<result column="name" property="name"/>
<result column="grade" property="grade"/>
<!--student是定义在Subject实体类中的对象属性,Student2是对象属性对应的实体类对象-->
<collection property="students" ofType="Student2">
<id column="stu_id" property="id"></id>
<result column="stu_name" property="name"/>
<result column="sex" property="sex"/>
</collection>
</resultMap>
<select id="querySubjectById" resultMap="subject_result">
select t_subjects.id,t_subjects.name,t_subjects.grade,
t_students.id stu_id,t_students.name stu_name,t_students.sex
from t_subjects join t_stu_sub
on t_subjects.id = t_stu_sub.subject_id
join t_students
on t_stu_sub.student_id = t_students.id
where t_subjects.id = #{id}
</select>
</mapper>
七、动态SQL
7.1 SQL片段抽取
在mapper映射文件中抽取出相同的SQL片段,用插入的方式使用片段,减少冗杂。
<sql id="user_field">
select id,username,password,gender,regist_time registTime
from t_user
</sql>
<select id="queryUserById" resultType="User">
<include refid="user_field"/>
where id=#{id}
</select>
7.2 if标签
当一个实体对应的Dao文件中要进行多个查询时,可以只定义一个Dao方法,在映射文件中使用If判断
// 假设User实体类中有id和username两个字段
User queryUser(User user)
<!--假设查询User两个字段的任意一个时,判断其不为空(另一个肯定为空),传入其中一个字段值查询-->
<select id="queryUser" resultType="User">
<include refid="user_field"/>
where
<if test="id!=null">
id=#{id}
</if>
<if test="username!=null">
username=#{username}
</if>
</select>
7.3 where标签
上述假设只传入一个值,当传入两个值时
// 假设User实体类中有username和gender两个字段
User queryUser(User user)
<!--加上一个or,表示当传入两个值时,两个值都将被带入查询-->
<!--where标签可以去除当传入一个值时可能存在的or或and开头的关键字,避免带入SQL语句查询-->
<select id="queryUser" resultType="User">
<include refid="user_field"/>
<where>
<if test="username!=null">
username=#{username}
</if>
<if test="gender!=null">
or gender=#{gender}
</if>
</where>
</select>
7.4 set标签
当一个实体对应的Dao文件中要进行多个更新时,可以只定义一个Dao方法,在映射文件中可以将set和if两个标签配合使用
User updateUser(User user)
<!--set标签可以去除字段后的逗号-->
<update id="updateUser" parameterType="User">
update t_user
<set>
<if test="username!=null">
username=#{username},
</if>
<if test="password!=null">
password=#{password},
</if>
<if test="gender!=null">
gender=#{gender},
</if>
<if test="registTime!=null">
registTime=#{registTime}
</if>
</set>
where id = #{id}
</update>
7.5 trim标签
trim标签综合了where和set标签,可替代两个标签
<select id="queryUser" resultType="User">
<include refid="user_field"/>
<!--此处trim标签的作用和where一样,去除or或者and开头的关键字-->
<trim prefix="where" prefixOverrides="or|and">
<if test="username!=null">
username=#{username}
</if>
<if test="gender!=null">
or gender=#{gender}
</if>
</trim>
</select>
<!--==============================================================================================-->
<update id="updateUser" parameterType="User">
update t_user
<!--此处trim标签的作用和set一样,去除结尾的逗号-->
<trim prefix="set" suffixOverrides=",">
<if test="username!=null">
username=#{username},
</if>
<if test="password!=null">
password=#{password},
</if>
<if test="gender!=null">
gender=#{gender},
</if>
<if test="registTime!=null">
registTime=#{registTime}
</if>
</trim>
where id = #{id}
</update>
7.6 foreach标签
批量操作使用foreach标签进行遍历
批量删除
Integer deleteManyUser(List<Integer> ids)
<delete id="deleteManyUser" parameterType="java.util.List">
<!--delete from t_user where id in(x,x,x,x,x,x)-->
delete from t_user where id in
<!--collection表示遍历参数的类型,item表示每次遍历出的值,separator表示用逗号做分隔-->
<foreach collection="list" open="(" close=")" item="id9" separator=",">
#{id9}
</foreach>
</delete>
批量插入
Integer insertManyUser(List<User> users)
<insert id="insertManyUser" parameterType="java.util.List">
<!--insert into t_user values(null,x,x,x,x)-->
insert into t_user values
<!--open和close不规则空着-->
<foreach collection="list" open="" close="" item="user9" separator=",">
(null,#{user9.username},#{user9.password},#{user9.gender},#{user9.registTime})
</foreach>
</insert>
八、缓存
缓存:内存中的一块储存控件,服务于某个应用程序,旨在将频繁读取的数据临时保存在内存中,便于二次访问
- 无缓存:用户访问数据时,需要发起多次对数据库的访问,导致产生大量IO,读写硬盘操作,效率低下
- 有缓存,首次访问,查询数据库,将数据储存到缓存中;再次访问时,直接访问缓存,减少IO、硬盘读写次数、提高效率
8.1 一级缓存
SqlSession级别缓存,同一个SqlSession发起多次同构查询,会将数据保存在一级缓存中
作用域是一个SqlSession,无法跨域
默认开启以及缓存
8.2 二级缓存
SqlSessionFactory级别缓存,同一个SqlSessionFactory构建的SqlSession发起的多次同构查询,会将数据保存在二级缓存中
只有在查询结束(释放资源)后才会进入二级缓存
在sqlSession.commit()或者sqlSession.close()之后生效
<!--配置文件中二级缓存默认开启-->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!--mapper中被cache标签包裹的查询语句才能进入二级缓存-->
<cache>
<insert>...</insert>
<delete>...</delete>
<select>...</select>
<update>...</update>
</cache>
九、Druid连接池
在pom中导入依赖
<!--Druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
创建MyDruidDataSourceFactory
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
public class MyDruidDataSourceFactory extends PooledDataSourceFactory {
public MyDruidDataSourceFactory(){
this.dataSource = new DruidDataSource();//替换数据源
}
}
修改数据库连接参数
<!--数据库连接参数-->
<dataSource type="util.MyDruidDataSourceFactory">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</dataSource>
十、分页插件PageHelper
10.1 概念
PageHelper是适用于MyBatis框架的一个分页插件,使用方式便捷,支持任何发咋单表、多表分页查询操作
10.2 访问与下载
官网:https://pagehelper.github.io/
下载:https://github.com/pagehelper/Mybatis-PageHelper
10.3 使用步骤
- 在pom中导入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.10</version>
</dependency>
在配置文件中安装(mybatis-config.xml)
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
简单使用
//假设要查寻出某张表所有的数据,使用PageHelper分页
//在调用查询方法的前一步使用PageHelper插件
//第一个参数表示查第几页,第二个参数表示没有显示几条数据
PageHelper.startPage(1, 2);
List<User> userList = mapper.findAll();
//封装list到 PageInfo对象中自动分页
PageInfo<User> userPageInfo = new PageInfo<>(userList);
- 只有在PageHelper.startPage();方法之后的第一个查询会有分页
- 分页插件不支持带有‘for update’的查询语句
- 分页插件不支持嵌套查询,由于嵌套结果方式会导致结果集被折叠,无法保证分页结果数量正确
十一、注解使用
当SQL语句比较简单时,可以在Dao方法上方写注解代替映射文件
//@Select @Update @Delete @Insert操作都是相同的
@Select("select id,username,password,gender,regist_time registTime from t_user where id=#{id}")
User queryUserById(Integer id);
//主键回填,写在@Insert上方
@Options(useGeneratedKeys = true,keyProperty = "id")
十二、${}和#{}
12.1 区别
#{}
匹配的是一个占位符,相当于JDBC中的一个?
,会对一些敏感的字符进行过滤,编译过后会对传递的值加上双引号,因此可以防止SQL注入问题。${}
匹配的是真实传递的值,传递过后,会与sql语句进行字符串拼接。${}
会与其他sql进行字符串拼接,不能预防sql注入问题。(一般用于对sql片段进行拼接,比如表名和升序降序等,不能用于传值)
十三、嵌套查询
13.1 概念
嵌套查询就是将原来多表查询中的联合查询语句拆成单个表的查询,再使用mybatis的语法嵌套在一起
12.2 步骤
1.从表编辑对应Dao和mapper进行单表查询
List<Employee> queryEmployeeByDeptId(@Param("dept_id") Integer dept_id);
<select id="queryEmployeeByDeptId" resultType="Employee">
select id,name,salary
from t_departments
where dept_id=#{dept_id}
</select>
2.主表也进行对应的单表查询,并使用resultMap对第一个表的查询方法进行嵌套
Department queryDepartmentById(@Param("id") Integer id);
<resultMap id="department_result" type="Department">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="location" property="location"></result>
<!--employee是主表实体类中的对象属性名-->
<!--嵌套queryEmployeeByDeptId方法查询-->
<!--queryEmployeeByDeptId方法查询所用的字段为外键,值与主表主键字段相同,column-->
<collection property="employee" ofType="Employee"
select="dao.EmployeeDao.queryEmployeeByDeptId" column="id">
</collection>
</resultMap>
<select id="queryDepartmentById" resultMap="department_result">
select id,name,location
from t_departments
where id=#{id}
</select>