目录
中文网:MyBatis中文网
一、MyBatis简介
1、MyBatis的历史
MyBatis 本是 Apache 的一个开源项目 iBatis,2010年这个项目由 Apache Software Foundation 迁移到了Google Code,并且改名为 MyBatis 。2013年11月迁移到 Github。
iBatis一词来源于 "internet"和 "abatis"的组合,是一个基于Java的持久层框架。iBatis 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAO)。
2、MyBatis的特性
- MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
- MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
- MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录
- MyBatis是一个半自动的ORM框架
3、和其它持久化层技术的比较
JDBC:
SQL夹杂在Java代码中耦合度高,导致硬编码内伤维护不易且实际开发需求中SQL有变化,频繁修改的情况多见
代码冗长,开发效率低
Hibernate和JPA
操作简便,开发效率高
程序中的长难复杂SQL需要绕过框架
内部基于自动生产的SQL,不容易做特殊优化
基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难
反射操作太多,导致数据库性能下降
MyBatis
轻量级,性能出色
SQL和Java编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据
开发效率稍逊于Hibernate,但是完全能够接受
二、搭建MyBatis
1、开发环境
IDE:idea 2023.3.4
构建工具:maven 3.8.1
MySQL版本:MySQL 8.0.32
MyBatis版本:MyBatis 3.5.5
2、创建Maven工程
打包方式使用jar
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<packaging>jar</packaging>
<dependencies>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
<!--MyBatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<!-- <scope>test</scope>-->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
</plugin>
</plugins>
</build>
</project>
3、创建MyBatis核心配置文件
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)
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>
<!--配置连接数据库的环境-->
<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://localhost:3306/aaa_test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<mapper resource="cn/ysy/mapper/StudentMapper.xml"/>
</mappers>
</configuration>
4、创建mapper接口
MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类
实体类三个属性
5、创建Mybatis的映射文件
相关概念:ORM(Object Relationship Mapping)对象关系映射。
对象:Java的实体类对象关系:关系型数据库
映射:二者之间的对应关系
Java概念 | 数据库概念 |
类 | 表 |
属性 | 字段/列 |
对象 | 记录/行 |
1、映射文件的命名规则
表所对应的实体类的类名+Mapper.xml
例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml
因此一个映射文件对应一个实体类,对应一张表的操作
MyBatis映射文件用于编写SQL,访问以及操作表中的数据
MyBatis映射文件存放的位置是src/main/resources/mappers目录下
2、MyBatis中可以面向接口操作数据,要保证两个一致:
mapper接口的全类名和映射文件的命名空间(namespace)保持一致
mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致
<?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="cn.ysy.mapper.StudentMapper">
<insert id="insertStudent">
insert into student values(null,'ysy',18);
</insert>
</mapper>
6、测试功能
测试添加方法
@Test
public void test1() throws IOException {
//加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//获取SQLSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取mapper接口对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
int i = mapper.insertStudent();
//提交事务 因为mybatis-config.xml中设置了以JDBC的方式提交事务,所以这里需要手动提交事务
sqlSession.commit();
System.out.println(i);
}
SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
SqlSessionFactory:是"生产"SqlSession"的"工厂"。工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个"工厂类"中,以后都使用这个工厂类来"生产"我们需要的对象
7、功能优化
opSession(true);设置自动提交事务,默认是不自动提交的
光标放在openSession的参数括号里,ctrl+p可以查看所有参数
@Test
public void test1() throws IOException {
//加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//获取SQLSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession对象 这里设置为true之后,可以自动提交事务,就不需要手动提交了
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取mapper接口对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
int i = mapper.insertStudent();
//提交事务 因为mybatis-config.xml中设置了以JDBC的方式提交事务,所以这里需要手动提交事务
//sqlSession.commit();
System.out.println(i);
}
8、修改和删除方法的测试
@Test
public void testByUpdate() throws IOException {
//加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//获取SQLSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取mapper接口对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
mapper.updateStudent();
}
@Test
public void testByDel() throws IOException {
//加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//获取SQLSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取mapper接口对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
mapper.deleteStudent();
}
都是没有问题的
9、查询功能测试
查询一个实体对象,包括查询一个实体对象和查询一个list对象
@Test
public void testFindById() throws IOException {
//加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//获取SQLSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取mapper接口对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
Student student = mapper.findStudentById();
System.out.println(student);
}
@Test
public void testFindAll() throws IOException {
//加载核心配置文件
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//获取SQLSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取mapper接口对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
List<Student> all = mapper.findAll();
for (Student student : all) {
System.out.println(student);
}
}
三、核心配置文件详解
配置_MyBatis中文网:配置
具体的可以去中文网查看,配置的时候应按照以下顺序进行配置,否则会报错
1、environments(环境配置)
MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,
<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://localhost:3306/aaa_test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
注意一些关键点:
- 默认使用的环境 ID(比如:default="development")。
- 每个 environment 元素定义的环境 ID(比如:id="development")。
- 事务管理器的配置(比如:type="JDBC")。
- 数据源的配置(比如:type="POOLED")。
默认环境和环境 ID 顾名思义。 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID
1.1、transactionManager(事务管理器)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
1.2、dataSource(数据源)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
- 大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")
UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形
POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求
JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用
2、properties(属性)
jdbc.properties:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/aaa_test
jdbc.username=root
jdbc.password=123456
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:
设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:
<properties resource="jdbc.properties"/>
<!--配置连接数据库的环境-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
上面例子中的 username 和.password , driver 和 url 属性将会由 jdbc.properties 文件中对应的值来替换。这样就为配置提供了诸多灵活选择。
3、typeAliases(类型别名)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
当这样配置时,Student可以用在任何使用 cn.ysy.pojo.Student 的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean.
4、mapper(映射器)
创建resources下的文件目录时,要用斜杠(/),不能再使用创建包时的点号(.),要不然创建出来的目录不是层级的
将包内的映射器接口实现全部注册为映射,不用再一个一个映射器去注册了
其它标签我们遇到再说
四、封装SqlSessionUtils工具类并测试
SqlSessionutils:
public class SqlSessionUtil {
public static SqlSession getSqlSession(){
//获取配置文件
SqlSession sqlSession = null;
try {
InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
//获取SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
} catch (IOException e) {
throw new RuntimeException(e);
}
return sqlSession;
}
}
五、MyBatis获取参数的两种方式
MyBatis获取参数值的两种方式:${}和#{}
${}的本质就是字符串拼接,#{}的本质就是占位符赋值
${}使用字符串拼接的方式拼出sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号
1、情况1
mapper接口方法中的参数为单个的字面量类型
例子:根据用户名查询用户首先使用#{}去获取参数,运行程序是没有问题的
换成${name}再去执行程序就会报错实际执行的是:
select * from student where name = 张三 ; 很明显这个语句少了单引号,所以解决方法就是再${}外面天上单引号就可以了,再去执行项目就没有问题了
StudentMapper.java:
//根据用户名查询
Student findByName(String name);
StudentMapper.xml:
<select id="findByName" parameterType="string" resultType="Student">
select * from student where name = #{name};
</select>
@Test
public void testFindByName(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//获取mapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
Student student = mapper.findByName("张三");
//输出
System.out.println(student);
}
2、情况2
mapper接口方法中的参数为多个时
例子:根据用户名和年龄查询用户首先还是使用#{}去获取参数:
select * from student where name=#{name} and age=#{age}
这样看确实没啥问题,但是执行的时候报错
是因为:此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
1、以arg0,rag1...为键,以参数为值2、以param1,param2...为键,以参数为值
因此只需要通过#{}和${}以键的方式访问值即可,但需要注意${}的单引号问题
select * from student where name=#{arg0} and age=#{arg1}再去执行就没有问题了
StudentMapper.java:
//根据name和age查询
Student findByNameAndAge(String name,int age);
StudentMapper.xml:
<select id="findByNameAndAge" resultType="Student">
select * from student where name = #{arg0} and age = #{arg1};
</select>
@Test
public void testFindByNameAndAge(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//获取mapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
Student student = mapper.findByNameAndAge("张三",11);
//输出
System.out.println(student);
}
3、情况3
mapper接口方法中的参数为多个时,可以手动将这些参数放在一个map中存储
只需要通过#{}和${}以键的方式访问值即可,但是需要注意${}的单引号问题
//登录
Student login(Map<String,Object> map);
<select id="login" resultType="Student">
select * from student where name = #{name} and age = #{age};
</select>
@Test
public void testFindByMap(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//获取mapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//创建mao对象
Map<String, Object> map = new HashMap<>();
map.put("name","张三");
map.put("age",11);
//执行
Student student = mapper.login(map);
//输出
System.out.println(student);
}
4、情况4
mapper接口方法中的参数是实体类类型的参数
只需要通过#{}和${}以属性的方式访问属性值即可,但是需要注意${}的单引号问题
//添加用户信息
int add(Student student);
<insert id="add">
insert into student values(null,#{name},#{age});
</insert>
@Test
public void test7(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//获取mapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
int result = mapper.add(new Student(0, "张三", 11));
//输出
System.out.println(result);
}
5、情况5
使用@Param注解命名参数
此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储1、以@Param注解的值为键,以参数为值
2、以param1,param2...为键,以参数为值
因此只需要通过#{}和${}以键的方式访问值即可,但需要注意${}的单引号问题
//以参数形式查找用户
Student loginByParam(@Param("name") String name , @Param("age") int age);
<select id="loginByParam" resultType="Student">
select * from student where name = #{name} and age = #{age};
</select>
@Test
public void loginByParam(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
//获取mapper对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//执行
Student student = mapper.loginByParam("张三",11);
//输出
System.out.println(student);
}
六、 MyBatis的各种查询功能
1、查询结果只有一条
可以通过实体类对象接收
可以通过list集合接收
//根据用户id查询用户信息
Student testFindStudentById(@Param("id") int id);
<select id="testFindStudentById" resultType="Student">
select * from student where id = #{id};
</select>
@Test
public void findStudentById(){
//获取SqlSession
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.testFindStudentById(2);
System.out.println(student);
}
2、查询结果有多条
可以通过list集合接收
注意:一定不能通过实体类对象接收,此时会抛异常TooManyResultsException
//查询所有
List<Student> testFindAll();
<select id="testFindAll" resultType="Student">
select * from student
</select>
@Test
public void findStudentById(){
//获取SqlSession
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = studentMapper.testFindStudentById(2);
System.out.println(student);
}
3、MyBatis中默认的类型别名
java.lang.Integer-->int,integer
int --> _int,_integerMap-->map
String ---> string
//查询用户的总记录数
Integer testFindTotal();
<select id="testFindTotal" resultType="integer">
select count(*) from student
</select>
@Test
public void testFindTotal(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
System.out.println(studentMapper.testFindTotal());
}
4、查询的结果用map方式接收
结果:{name=王五, id=3, age=33}
//根据id查询用户信息为一个Map
Map<String,Object> testFindStudentByIdToMap(@Param("id") Integer id);
<select id="testFindStudentByIdToMap" resultType="map">
select * from student where id = #{id};
</select>
@Test
public void testFindStudentByIdToMap(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
System.out.println(studentMapper.testFindStudentByIdToMap(3));
}
5、查询多条数据用map接收
结果:[{name=李四, id=2, age=22}, {name=王五, id=3, age=33}, {name=赵六, id=4, age=44}, {name=ysy, id=6, age=18}, {name=ysy, id=7, age=18}, {name=张三, id=8, age=11}, {name=sy, id=9, age=21}]
在mapper接口方法上添加@MapKey注解,此时可以将每条数据转换的map集合作为值,以某个字段的值作为键,放在同一个map集合中
//查询所有用户信息,并将数据封装为map集合
List<Map<String,Object>> testFindAllToMap();
@MapKey("id") //以id为key
Map<String,Object> testFindAllToMap();
//结果:{2={name=李四, id=2, age=22}, 3={name=王五, id=3, age=33}, 4={name=赵六, id=4, age=44}, 6={name=ysy, id=6, age=18}, 7={name=ysy, id=7, age=18}, 8={name=张三, id=8, age=11}, 9={name=sy, id=9, age=21}}
<select id="testFindAllToMap" resultType="map">
select * from student
</select>
@Test
public void testFindAllToMap(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
System.out.println(studentMapper.testFindAllToMap());
}
七、特殊SQL的执行
1、模糊查询
//根据用户名模糊查询
List<Student> findByNameLike(@Param("name") String name);
<select id="findByNameLike" resultType="student">
<!--select * from student where name like '%${name}%'-->
<!--select * from student where name like concat('%',#{name},'%');-->
select * from student where name like "%"#{name}"%"
</select>
@Test
public void findNameByLike(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = studentMapper.findByNameLike("y");
System.out.println(students);
}
2、批量删除
//批量删除
int deleteMore(@Param("ids") String ids);
<delete id="deleteMore">
delete from student where id in (${ids})
</delete>
@Test
public void deleteMore(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
int i = studentMapper.deleteMore("2,3,4");
System.out.println(i);
}
3、动态设置表名
//动态设置表名,查询所有
List<Student> findMoreByTableName(@Param("tableName") String tableName);
<select id="findMoreByTableName" resultType="student">
select * from ${tableName}
</select>
@Test
public void findMoreByTableName(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper student = sqlSession.getMapper(StudentMapper.class);
List<Student> students = student.findMoreByTableName("student");
System.out.println(students);
}
4、添加功能获取自增主键
useGeneratedKeys:设置当前标签中的sql使用了自增的主键
keyProperty:将自增的主键的值赋值给传输到映射文件中参数的某个属性
//添加用户信息
void addStudent(Student student);
<insert id="addStudent" useGeneratedKeys="true" keyProperty="id">
insert into student values(null,#{name},#{age})
</insert>
@Test
public void addStudent(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = new Student(null, "ysy", 23);
studentMapper.addStudent(student);
System.out.println(student);
}
八、自定义映射resultMap
解决字段名和属性名不一致问题
1、方法一——给SQL语句的字段起别名
List<TbStudent> getAllStudent();
<select id="getAllStudent" resultType="TbStudent">
select * from tb_student;
</select>
@Test
public void testFindAll() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<TbStudent> students = mapper.getAllStudent();
//lambda
students.forEach(System.out::println);
}
当实体类 的属性名和数据库中的字段名对不上就差找不到该属性,就是显示null值,无法映射
通过给sql语句起别名可以解决
2、方法二 ——设置全局配置
<!--设置MyBatis的全局配置-->
<settings>
<!--将“_”下划线映射为驼峰————stu_name:stuName-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<select id="getAllStudent" resultType="TbStudent">
<!--select id,stu_name stuName,stu_age stuAge from tb_student;-->
select id,stu_name,stu_age from tb_student;
</select>
这样再去测试案例,就发现就没问题了
3、方法三——通过resultMap设置自定义的映射关系
id是映射主键的关系
result是映射普通字段的关系
<resultMap id="TbStudentMap" type="TbStudent">
<id property="id" column="id"/>
<result property="stuName" column="stu_name"/>
<result property="stuAge" column="stu_age"/>
</resultMap>
<select id="getAllStudent" resultMap="TbStudentMap">
select * from tb_student;
</select>
4、多对一的映射
4.1、级联属性赋值
//查询用户信息及所属班级的信息
TbStudent getStudentAndClass(@Param("id") Integer id);
<resultMap id="StudentAndClassesMapOne" type="TbStudent">
<id property="id" column="id"/>
<result property="stuName" column="stu_name"/>
<result property="stuAge" column="stu_age"/>
<result property="classes.cid" column="cid"/>
<result property="classes.claName" column="cla_name"/>
</resultMap>
<select id="getStudentAndClass" resultMap="StudentAndClassesMapOne">
<!--左外连接查询-->
select * from tb_student s left join classes c on s.cid = c.cid where s.id = #{id};
</select>
@Test
public void testFindStudentAndClassesById() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
TbStudent student = mapper.getStudentAndClass(1);
System.out.println(student);
}
4.2、association
<resultMap id="StudentAndClassesMapTwo" type="TbStudent">
<id property="id" column="id"/>
<result property="stuName" column="stu_name"/>
<result property="stuAge" column="stu_age"/>
<association property="classes" javaType="Classes">
<id property="cid" column="cid"/>
<result property="claName" column="cla_name"/>
</association>
</resultMap>
<select id="getStudentAndClass" resultMap="StudentAndClassesMapTwo">
<!--左外连接查询-->
select * from tb_student s left join classes c on s.cid = c.cid where s.id = #{id};
</select>
4.3、分布查询
前提把全局配置打开,避免getClassesStepTwo再用resultMap
select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)
column:设置分布查询的条件
<!--设置MyBatis的全局配置-->
<settings>
<!--将“_”下划线映射为驼峰————stu_name:stuName-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
//分布查询用户信息和班级信息
//第一步:查询用户信息
TbStudent getStudentStepOne(@Param("id") Integer id);
//第二步:查询班级信息
Classes getClassesStepTwo(@Param("cid") Integer cid);
<resultMap id="StudentStepOneMap" type="TbStudent">
<id property="id" column="id"/>
<result property="stuName" column="stu_name"/>
<result property="stuAge" column="stu_age"/>
<association property="classes"
select="cn.ysy.mapper.StudentMapper.getClassesStepTwo"
column="cid">
<id property="cid" column="cid"/>
<result property="claName" column="cla_name"/>
</association>
</resultMap>
<select id="getStudentStepOne" resultMap="StudentStepOneMap">
select * from tb_student where id = #{id};
</select>
<select id="getClassesStepTwo" resultType="Classes">
select * from classes where cid = #{cid};
</select>
@Test
public void testFindStudentAndClassesSept() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
TbStudent student = mapper.getStudentStepOne(1);
System.out.println(student);
}
分布查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
aggressiveLazyLoading:当开启时,任何地方的调用都会加载该对象的所有属性。否则,每个属性会按需加载
此时就要可以实现按需加载,获取的书库是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分布查询是否使用延迟加载,fetchType="lazy(延迟加载)eager(理解加载)"
5、一对多的映射
5.1、collection
collection:处理一对多的映射关系
ofType:表示该属性所对应的结合中存储数据的类型
//获取班级所有同学信息
Classes getAllStudentAndDept(@Param("cid") Integer cid);
<!--一对多关系映射-->
<resultMap id="ClassesAndStudentResultMap" type="Classes">
<id property="cid" column="cid"/>
<result property="claName" column="cla_name"/>
<!--collection表示一对多的关系-->
<collection property="studentList" ofType="TbStudent">
<id property="id" column="id"/>
<result property="stuName" column="stu_name"/>
<result property="stuAge" column="stu_age"/>
</collection>
</resultMap>
<select id="getAllStudentAndDept" resultMap="ClassesAndStudentResultMap">
<!--使用calsses左外连接查询,左表是classes-->
select * from classes c left join tb_student s on c.cid = s.cid where c.cid = #{cid};
</select>
@Test
public void getAllStudentAndDept() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Classes classes = mapper.getAllStudentAndDept(1);
System.out.println(classes);
}
5.2、分布查询
//分步查询班级信息以及班级下的所有同学信息
Classes getClassesAndStudentStepOne(@Param("cid") Integer cid);
//第二步:根据cid查询班级下的所有同学信息
List<Student> getClassesAndStudentStepTwo(@Param("cid") Integer cid);
<resultMap id="ClassesAndStudent" type="Classes">
<id property="cid" column="cid"/>
<result property="claName" column="cla_name"/>
<collection property="studentList"
select="cn.ysy.mapper.StudentMapper.getClassesAndStudentStepTwo"
column="cid">
</collection>
</resultMap>
<select id="getClassesAndStudentStepOne" resultMap="ClassesAndStudent">
select * from classes where cid = #{cid};
</select>
<select id="getClassesAndStudentStepTwo" resultType="tbStudent">
select * from tb_student where cid = #{cid};
</select>
@Test
public void getClassesAndStudentStep() {
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Classes classes = mapper.getClassesAndStudentStepOne(1);
System.out.println(classes);
}