Mybatis基础教程
一、简介
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
需要使用到的jar包:
- mysql-connector-java.jar
- mybatis.jar
注:如果使用maven创建项目的化,可以取maven仓库找到对应的mybatis包,再导入xml就好。
1、持久化的简介
数据持久化:
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库(Jdbc),io文件持久化。
持久层:
例如:DAO层、Service层、Controller层
- 完成持久化工作的代码块
- 底层界限十分明显
2、Mybatis的特点
- 方便写入数据到数据库中。
- 不需要再写传统的JDBC代码,简化了代码,自动化。
- sql和代码分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射。
- 提供对象关系映射标签,支持对象关系组建维护。
- 提供xml标签,支持编写动态sql。
二、创建一个简单的Mybaits程序
在此之前需要新建一个数据库数据;
CREATE DATABASE `mybatis`;
USE `mybatis`;
CREATE TABLE `user`(
`id` INT(20) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
--自行插入数据到数据表中;
接下来创建一个项目,导入所需要的所有Jar包,然后就可以编写代码了;
创建一个database.properties,用来定义JDBC数据连接数据库:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql:/本机地址:3306/数据库?useUnicode=true&characterEncoding=utf-8&useSSL=true
username=数据库账号
password=密码
最重要的一点,编写mybaits-config.xml核心配置:
(可以查看Mybatis开发文档:https://mybatis.org/mybatis-3/zh/index.html)
<?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核心配置文件-->
<configuration>
<!-- 获取配置文件database.properties -->
<properties resource="database.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"></transactionManager>
<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>
<!-- 每一个Mapper.xml都需要在Mybatis核心配置中注册! -->
<mappers>
<mapper resource="com/vxzx/dao/UserMapper.xml"></mapper>
</mappers>
</configuration>
可以再编写一个获取Mybatis的Sqlsession的工具类:
package com.vxzx.utils;
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;
//该配置是固定的:
public class MybatisUtils {
//获取SqlSessionFactory对象:
public static SqlSession getsqlSession(){
SqlSession session = null;
String resource = "mybaits-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
session = sessionFactory.openSession();
} catch (IOException e) {
e.printStackTrace();
}
return session;
}
}
- pojo层的User类:
package com.vxzx.pojo;
public class User {
private Integer id;
private String name;
private String pwd;
public User() {
}
public User(Integer id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
- UserMapper接口:
package com.vxzx.dao;
import com.vxzx.pojo.User;
import java.util.List;
import java.util.Map;
public interface UserMapper {
//获取所有用户信息:
List<User> getUserList();
//添加一个用户:
int addUser(User user);
//使用map修改用户:
int updateUser2(Map<String,Object> map);
//模糊查询:
List<User> getUserByLike(String value);
}
- UserMapper.xml (在这里面类似于编写以前的JDBC查询代码:)
<?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">
<!-- namespace命名空间=绑定的一个对应的Mapper接口 -->
<mapper namespace="com.vxzx.dao.UserMapper">
<!-- select:查询语句; id:对应引用的方法名;resultType:返回结果集 -->
<select id="getUserList" resultType="com.vxzx.pojo.User">
select * from user
</select>
-- 只能修改pwd的数据,不能修改其他的数据:
<insert id="addUser" parameterType="com.vxzx.pojo.User">
insert into user(id,name,pwd) values(#{id},#{name},#{pwd})
</insert>
<update id="updateUser2" parameterType="map">
update user set name=#{username},pwd=#{password} where id=#{id}
</update>
<select id="getUserByLike" resultType="com.vxzx.pojo.User">
select * from user where name like #{value}
</select>
</mapper>
- UserMapperTest测试类:
//查询所有用户信息:
public void getUserList(){
//1、获取SqlSession对象:
SqlSession session = MybatisUtils.getsqlSession();
//2、执行SQL: ----方式一:推荐使用
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
//2、执行SQL: ----方式二:
// List<User> userList = session.selectList("com.vxzx.dao.UserMapper.getUserList");
for (User user : userList) {
System.out.println(user);
}
session.close();
}
//添加用户:
public void addUser(){
SqlSession session = MybatisUtils.getsqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int user1 = mapper.addUser(new User(5, "vxzx", "123"));
if (user1 > 0){
System.out.println("添加成功!");
}
//提交事务:必须执行,不然添加不进去
session.commit();
session.close();
}
//使用map修改用户:
public void updateUser(){
SqlSession session = MybatisUtils.getsqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String, Object>();
//格式:(sql语句中的#{}的值,新的值);可以插入一个或多个,不用全部插入
map.put("username","vx");
map.put("password","111111");
map.put("id",4);
mapper.updateUser2(map);
session.commit();
session.close();
}
//模糊查询:
public void getUserByLike(){
SqlSession session = MybatisUtils.getsqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> userList = mapper.getUserByLike("%x%");
for (User user : userList) {
System.out.println(user);
}
session.close();
}
如果出现配置文件无法导出或者生效的问题,可以在项目对应的pom.xml插入以下配置代码:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
三、Mybatis的CRUD
接下来,我们可以对上面代码进行详细的解析:
1、namespace
namespace中的包名要和 Dao/mapper 接口的包名一致!
2、select
选择,查询语句;
- id : 就是对应的namespace中的方法名;
- resultType:Sql语句执行的返回值!
- parameterType : 参数类型!
2.1 编写接口
//根据ID查询用户
User getUserById(int id);
2.2 编写对应的mapper的sql语句
<select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
select * from mybatis.user where id = #{id}
</select>
2.3 测试
public void getUserById() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
3、Insert
3.1 编写对应的mapper的sql语句
<!--对象中的属性,可以直接取出来-->
<insert id="addUser" parameterType="com.kuang.pojo.User">
insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
</insert>
4、update
4.1 编写对应的mapper的sql语句
<update id="updateUser" parameterType="com.kuang.pojo.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id = #{id} ;
</update>
5、delete
5.1 编写对应的mapper的sql语句
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id = #{id};
</delete>
注意:增删改需要使用commit()
提交事务;
6、使用map来定义数据中的数据
假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map!
6.1 编写代码
- 编写接口类:
//万能的Map
int updateUser(Map<String,Object> map);
- 编写对应的mapper的sql语句
<update id="updateUser2" parameterType="map">
update user set name=#{username},pwd=#{password} where id=#{id}
</update>
- 编写测试类:
public void updateUser(){
SqlSession session = MybatisUtils.getsqlSession();
UserMapper mapper = session.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String, Object>();
//格式:(sql语句中的#{}的值,新的值);可以插入一个或多个,不用全部插入
map.put("username","vx");
map.put("password","111111");
map.put("id",4);
mapper.updateUser2(map);
session.commit();
session.close();
}
6.2 注意点
Map传递参数,直接在sql中取出key即可! 【parameterType="map"】
对象传递参数,直接在sql中取对象的属性即可!【parameterType="Object"】
只有一个基本类型参数的情况下,可以直接在sql中取到!
多个参数用Map,或者注解!
7、Mybatis的模糊查询
7.1 Java代码执行的时候,传递通配符 % %
对应的mapper的sql语句:
<select id="getUserByLike" resultType="com.vxzx.pojo.User">
select * from user where name like #{value}
</select>
测试类中获取数据:
List<User> userList = mapper.getUserLike("%李%"); //加上通配符 % %
7.2 在sql拼接中使用通配符% %
一:对应的mapper的sql语句:
<select id="getUserByLike" resultType="com.vxzx.pojo.User">
select * from user where name like "%"#{value}"%"
</select>
测试类中获取数据:
List<User> userList = mapper.getUserLike("李"); //在mapper中已加通配符,这里不用加了
四、Mybatis配置详解
核心配置文件:
- configuration(配置)
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
- environment(环境变量)
- transactionManager(事务管理器)一般都为JDBC
- dataSource(数据源)一般都为POOLED,配置连接数据的数据源
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
注意:各种配置必须严格按照其固定的顺序来使用。
1、 配置之属性
(1)属性(properties)
使用properties来引用外部数据源;例如:引入JBDC数据库连接;【database.properties】
这些属性都是可外部配置且可动态替换的,既可以在典型的 Java 属性文件中配置,亦可通过 properties 元素的子元素来传递。
database.properties:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true
username=root
password=123456
在核心配置中直接引入:
<properties resource="database.properties"/>
在核心配置中添加一些配置:
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="pwd" value="11111"/>
</properties>
注意:如果两个文件有同一个字段,那么会优先使用外部的配置信息。
(2)环境配置(environments)
Mybatis可以配置多种环境来使用;但是每个SqlSessionFactory实例只能使用一种配置。
其中,Mybatis默认的transactionManager一般为JDBC,dataSource为POOLED连接池。
- default:环境配置默认选择的配置;
- id:每个配置的标志,用以来区分各个配置;
<environments default="environment">
<environment id="environment">
<transactionManager type="JDBC"></transactionManager>
<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、 配置之别名
(1)设置(settings)
MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。
例如:配置日志文件实现;
<settings>
<setting name="logImpl" value="log4j"/>
</settings>
(2)类型别名(typeAliases)
- 别名的存在是为java类型设置一个简短的名字;
- 可以减少类完全限定名的冗余;
使用
<typeAliases>
<package name="com.vxzx.pojo"/>
</typeAliases>
使用
其中type为需要设置的类,alias为设置的别名。
<typeAlias type="com.vxzx.pojo.User" alias="user"></typeAlias>
在
@Alias("user")
pubic class user(){}
3、 配置之映射器
- MapperRegistry:注册绑定我们的Mapper文件
- 配置对应的mapper映射文件 .xml
- 每一个Mapper.XML都需要在Mybatis核心配置文件中注册
我们有三种方法可以使用:
一:常用(无其他注意点)
<mappers>
<mapper resource="com/kuang/dao/UserMapper.xml"/>
</mappers>
二:使用class文件绑定注册
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>
注意:
- 接口与其对应的Mapper配置必须同名
- 接口与其对应的Mapper配置必须在听一个包下面
三:使用扫描包的方式注册绑定
<mappers>
<package name="com.kuang.dao"/>
</mappers>
注意:
- 接口与其对应的Mapper配置必须同名
- 接口与其对应的Mapper配置必须在听一个包下面
4、 生命周期与作用域
它的过程可以简单的理解为:创建sql工厂,打开sqlSession,使用Mapper来操作CRUD;
SqlSessionFactoryBuilder
- 用来创建SqlSessionFactory,一旦创建完成,SqlSessionFactoryBuilder将被销毁。
- 可以设置为局部变量,因为只需要使用一次。
SqlSessionFactory
- 一旦创建,SqlSessionFactory 将会存在于您的应用程序整个运行生命周期中。
- 因此 SqlSessionFactory 的最佳作用域是应用作用域。
- 最简单的就是使用单例模式或者静态单例模式。
SqlSession
- 连接到连接池的一个请求!
- SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
- 每个SqlSession里面可以有多个mapper业务。
- 用完之后需要赶紧关闭,否则资源被占用!
5、 属性名与字段名不一致
实体类的属性名:
private Integer id;
private String name;
private String password;
数据库的字段名:
id int(3) ;
name varchar(10) ;
pwd varchar(20) ;
其中,password与pwd就有区别。这样查询数据会查询出null。
解决方法一:直接在查询语句中设置别名as
<select id="getUserList" resultMap="resultmap">
select id,name,pwd as password from user
</select>
解决方法二:使用resultMap结果映射
- id:查询语句使用的resultMap名字;
- type:映射的结果集类;
- property:类中的属性名;
- column:数据库中的字段名;
<resultMap id="resultmap" type="user">
<!-- property:属性名; column:数据库字段名; -->
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="password" column="pwd"/>
</resultMap>
<select id="getUserList" resultMap="resultmap">
select * from user
</select>
对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。
你已经对它相当了解了,就不需要显式地用到他们。
6、实现分页
(1)使用limit分页
使用limit分页跟在sql里面的使用步骤一样,不同的是,需要在xml中填加该语句。
<!-- 将查询出来的结果从1开始,每页展示三个 -->
<select id="getUserlistLmit" resultType="user">
select * from mybatis.user limit 0,3;
</select>
(2)使用RowBounds分页
Mybatis提供了一个简单的逻辑分页使用类RowBounds。
首先,第一步先实例化一个RowBounds对象,里面输入的值为数据(起始值,显示页面值)
public RowBounds(int offset, int limit)
然后使用SQLsession中的selectList方法:
List<User> userList = sqlSession.selectList("com.vxzx.dao.UserMapper.getUserList", null, rs);
//传入的值:(需要查询的类的接口--及里面的方法,Object,RowBounds)
public void getUserListRow(){
//实现从第一开始,每页显示2条数据的显示;
RowBounds rs = new RowBounds(0,2);
SqlSession sqlSession = MybatisUtils.getSqlSession();
//注意,要使用selectList的方法;
List<User> userList = sqlSession.selectList("com.vxzx.dao.UserMapper.getUserList", null, rs);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
了解一些分页插件: PageHelper
五、日志
1、 日志工厂
数据库操作出现问题,就可以使用日志文件来进行排错。
Mybatis中日志的具体实现,可以在settings(设置)中设置。
在Mybatis核心配置文件中配置:
<settings>
<setting name="logImpl" value="log4j"/>
</settings>
还可以自己设置日志数据输出格式和路径:(log4j.properties)
2、Log4j
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件;过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程;通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
具体使用步骤:
(1)导入log4j的jar包:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
(2)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/vx.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=""/>
</settings>
实际使用操作:
- 在要使用log4j的类中,导入包 org.apache.log4j.Logger;
- 日志对象,参数为当前类的class
import org.apache.log4j.Logger;
static Logger logger = Logger.getLogger(UserMapperTest.class);
- 日志级别:
logger.info("输出的logger--->info");
logger.debug("输出的logger--->debug");
logger.error("输出的logger--->error");
3、扩展:使用注解开发
sql数据库的CURD我们都可以使用注解来进行简单的操作;
- 查询:
@Select("select * from user where id=#{uid}")
User getId(@Param("uid")int id);
- 添加:
@Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
int insertUser(User user);
- 修改
@Update("update user set name=#{name} where id=#{id}")
int updateUser(User user);
- 删除
@Delete("delete from user where id=#{uid}")
int deleteUser(@Param("uid")int id);
值得注意的一点是,需要在核心配置文件中绑定接口!
<!-- 使用注解方法=====绑定接口: -->
<mappers>
<mapper class="com.vxzx.dao.UserMapper"></mapper>
</mappers>
4、Lombok
Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。出现的神奇就是在源码中没有getter和setter方法,但是在编译生成的字节码文件中有getter和setter方法。这样就省去了手动重建这些代码的麻烦,使代码看起来更简洁些。
使用步骤:
- 导入jar包;也可以添加maven依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
- 然后,在我们需要使用的实体类上面,添加上
@Data
//导入lombok的jar包,使用Lombok注解,完成getter、setter
@Data //etter、setter
@AllArgsConstructor //有参构造
@NoArgsConstructor //无参构造
@EqualsAndHashCode //hashcode比较
@ToString
public class User {
private Integer id;
private String name;
private String password;
}
六、SQL多数据处理
1、多对一处理
例如:多个学生对应一个老师的例子。
- 对于学生来说,多个学生关联一个老师;----对象association
- 对于老师来说,一个老师有很多学生;----集合collection
多对一查询:使用<resultMap>中的association;
具体实现一:根据结果集映射查询
先使用sql连表查询语句===>映射为resultMap;
再使用resultMap,配置查询的数据的别名的问题,其中需要使用association,
再在association里面配置数据库列信息;
具体实现二:嵌套查询:
先使用sql语句查询第一个表中的数据===>映射为resultMap;
再使用resultMap,配置查询的第一个表;其中需要使用到association,
注意的是,association里面不必在写查询语句了,只需要在标签处配置
需要查询的第二个表的信息;
接着,再查询第二表的信息,要与上面的resultMap进行配对。
对于这种问题,我们有两种方法:
实体类:
public class Student {
private Integer id;
private String name;
private Teacher teacher;
}
接口类:
public List<Student> getStudent();
public List<Student> getStudent2();
第一种:根据查询嵌套处理
<!-- 多对一 方式一:-->
<select id="getStudent" resultMap="st">
select * from student
</select>
<!-- 复杂的属性需要:association->对象; collection->集合 -->
<resultMap id="st" type="student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
select * from teacher where id=#{tid}
</select>
第二种:按结果查询嵌套
<select id="getStudent2" resultMap="st2">
select student.id as sid,student.name as sname,teacher.name as tname
from student,teacher
where student.tid = teacher.id
</select>
<resultMap id="st2" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
2、一对多处理
例如:一个老师对应多个学生;
一对多查询:使用<resultMap>中的collection;
具体实现一:根据结果集映射查询
先使用sql连表查询语句===>映射为resultMapp;
在使用resultMap,配置查询语句的数据的别名问题,其中需要使用到collection;
再在collection中配置查询数据库列的信息;
注意的是:
相较于association,还需要多配置实体类中对应的
ofType(集合中获取泛型信息);
具体实现二:嵌套查询:
先使用sql语句查询第一个表中的数据===>映射为resultMap;
在使用resultMap,配置查询的第一个表;其中是要到的collection;
注意的是,collection里面不必在写查询语句了,只需要在标签处配置;
注意的是:
相较于association,还需要多配置实体类中对应的
javaType(指定属性的类型),ofType(集合中获取泛型信息);
最后,再进行查询第二个表,要与上面的resultMap进行配对;
对于这种问题,我们有两种方法:
实体类:
public class Student {
private Integer id;
private String name;
private Integer tid;
}
public class Teacher {
private Integer id;
private String name;
List<Student> students;
}
接口类:
List<Teacher> getTeacher(@Param("tid") int id);
List<Teacher> getTeacher2(@Param("tid") int id);
第一种:根据查询嵌套处理
<!-- collection 方式一: -->
<select id="getTeacher" resultMap="ts">
select * from teacher where id = #{tid}
</select>
<resultMap id="ts" type="teacher">
<collection property="students" javaType="ArrayList"
ofType="Student" column="id" select="getstudent">
</collection>
</resultMap>
<select id="getstudent" resultType="student">
select * from mybatis.student where tid = #{tid};
</select>
第二种:按结果查询嵌套
<!-- collection 方式二: -->
<select id="getTeacher2" resultMap="ts2">
select s.id as sid,s.name as sname,t.name as tname,t.id as tid
from student as s,teacher as t
where s.tid = t.id and t.id = #{tid};
</select>
<resultMap id="ts2" type="teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- javaType="" 指定属性的类型!
集合中获取泛型信息,需要使用ofType获取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
3、总结
- 关联-----association【多对一】
- 集合-----collection【一对多】
- javaType 与 ofType
- javaType用来指定实体类中属性的类型
- ofType用来指定映射到List或集合中的pojo的类型,泛型中的约束类型
七、动态SQL
动态 SQL 是 MyBatis 的强大特性之一。借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
简单来说,动态SQL就是指根据不同的条件生成不同的SQL语句。
- if
- choose(when,otherwise)
- trim(where,set)
- foreach
1、if
接口编写:
//动态sql:if
public List<Blog> getBlogm(Map<String,String> map);
mapper配置编写:
<!-- 动态 SQL·if: -->
<select id="getBlogm" resultType="blog" parameterType="map">
select * from mybatis.blog
<where>
<if test="title != null">
and title = "blog1"
</if>
<if test="author != null">
and author = "zx"
</if>
</where>
</select>
测试编写:
public void getBlogm(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap<String,String> map = new HashMap();
map.put("title","blog1");
List<Blog> blogm = mapper.getBlogm(map);
System.out.println(blogm);
sqlSession.close();
}
2、choose (when, otherwise)
- 相当于SQL语句中的条件筛选语句
其中接口类,测试类的配置基本都是一样的。
<!-- choose (when, otherwise): -->
<select id="getBlogmChoose" resultType="blog" parameterType="map">
select * from mybatis.blog
<where>
<choose>
<when test=" title != null">
and title = "title1"
</when>
<otherwise>
and id = 2
</otherwise>
</choose>
</where>
</select>
3、trim (where, set)
- 相当于SQL语句中的修改语句
<update id="updateTrim" parameterType="map">
update mybatis.blog
<set>
title=#{title}
</set>
where id=#{id}
</update>
4、foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
<!-- foreach: -->
<select id="getBlogmFe" parameterType="map" resultType="blog">
select * from mybatis.blog where id in
<foreach collection="list" item="item" index="1" open="(" separator="," close=")">
#{item}
</foreach>
</select>
注意:
-
collection:指你需要迭代的对象;
-
item:集合项,在下面需要使用;
-
index:索引值;
-
open:迭代值开始的符号;
-
separator:迭代值中间的分隔符;
-
close:迭代值结尾的符号;
5、SQL片段
有的时候,我们可能会将一些功能的部分抽取出来,方便复用!这时候,我们就需要用到SQL片段了。
在代码中使用<sql>
标签抽取公共代码,然后使用<include>
标签在需要的地方引用公共代码片段。
- 使用SQL标签抽取公共的部分
<!-- SQL片段: -->
<sql id="psql">
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
- 在需要使用的地方使用Include标签引用即可
<select id="getBlogm" resultType="blog" parameterType="map">
select * from mybatis.blog
<where>
<include refid="psql"></include>
</where>
</select>
八、简述缓存
一级缓存:存在于每一个测试类中,即一脱离了这个测试类,缓存就会被自动删除。默认开启
二级缓存:存在于每一个对应的Mapper中,即脱离了这个Mapper,缓存就会删除。需要手动开启
其中,开启二级缓存:
1、开启全局缓存
<!--显示的开启全局缓存-->
<setting name="cacheEnabled" value="true"/>
2、在需要使用的二级缓存的Mapper中使用:
<!--在当前Mapper.xml中使用二级缓存-->
<cache/>
也可以自定义缓存参数:
<!--在当前Mapper.xml中使用二级缓存-->
<cache eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
注意:开启二级缓存的时候,我们需要将实体类序列换,不然会出错。