Mybatis笔记
中文文档:
1、mybatis入门步骤
第一步:mybatis核心配置文件
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://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.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 每一个mapper.xml都需要在mybatis核心配置文件中注册-->
<mappers>
<mapper resource="com/test/dao/UserMapper.xml"/>
</mappers>
</configuration>
第二步:编写mybatis工具类
//工具类SqlSessionFactory
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static{
try {
//使用mybayis第一步获取SqlSessionFactory
String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
编写代码
第三步:实体类
package com.test.pojo;
public class User {
private long id;
private String name;
private String pwd;
public long getId() {
return id;
}
public void setId(long 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;
}
public User(long id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public User() {
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
第四步:接口
package com.test.dao;
import com.test.pojo.User;
import java.util.List;
public interface UserDao {
List<User> getUserList();
}
第五步:接口实现类,由原来的接口实现类转变位配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace=绑定一个对应的dao/mapper接口-->
<mapper namespace="com.test.dao.UserDao">
<select id="getUserList" resultType="com.test.pojo.User">
select * from mybatis.user;
</select>
</mapper>
测试
junit测试
第六步:测试类
public class UserDaoTest {
@Test
public void test(){
//获取sqlsession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//方式1:getmapper
UserDao mapper = sqlSession.getMapper(UserDao.class);
List<User> userList = mapper.getUserList();
for(User user:userList){
System.out.println(user);
}
//关闭sqlSession
sqlSession.close();
}
}
<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>false</filtering>
</resource>
</resources>
</build>
2、crud
1、namespace
namespace中的包名要和Dao/mapper接口的包名一致
2、select
<select id="getUserById" parameterType="int" resultType="com.test.pojo.User">
select * from mybatis.user where id = id;
</select>
id:就是对应的namespace中的方法名:
resultType:sql语句执行的返回值
parameterType:参数类型
编写接口
public interface UserMapper {
//查询全部用户
List<User> getUserList();
//根据id查询用户
User getUserById(int id);
//insert插入一个用户
Integer addUser(User user);
//修改用户
int updateUser(User user);
//删除用户
int deleteUser(int id);
}
编写mapper
<select id="getUserList" resultType="com.test.pojo.User">
<!-- resultType返回一个结果,这里返回的时实体类User结果-->
select * from mybatis.user
</select>
<select id="getUserById" parameterType="int" resultType="com.test.pojo.User">
select * from mybatis.user where id = #{id};
</select>
<!-- 对象中的属性,可以直接取出来-->
<insert id="addUser" parameterType="com.test.pojo.User">
insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd});
</insert>
<update id="updateUser" parameterType="com.test.pojo.User">
update mybatis.user set name = #{name},pwd=#{pwd} where id = #{id};
</update>
<delete id="deleteUser" parameterType="int" >
delete from mybatis.user where id = #{id};
</delete>
编写测试类,值得注意的是,增删改需要提交事务
//根据id查询
@Test
public void getUserById(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
//增加
@Test
public void addUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Integer res = mapper.addUser(new User(5,"白龙马","123456"));
if(res>0){
System.out.println("成功");
}
//提交事务
sqlSession.commit();
sqlSession.close();
}
//更新
@Test
public void updateUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(4,"唐僧111","123123"));
sqlSession.commit();
sqlSession.close();
}
//删除
@Test
public void deleteUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(4);
sqlSession.commit();
sqlSession.close();
}
配置解析
mabatis-config.xml
MyBatis的配置文件包含了会深深影响MyBatis行为的设置和属性信息
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
3、环境配置(environments)
MyBatis 可以配置成适应多种环境
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。
除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源:
poolMaximumActiveConnections – 在任意时间可存在的活动(正在使用)连接数量,默认值:10
poolMaximumIdleConnections – 任意时间可能存在的空闲连接数。
poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
poolTimeToWait – 这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。
poolMaximumLocalBadConnectionTolerance – 这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过 poolMaximumIdleConnections 与 poolMaximumLocalBadConnectionTolerance 之和。 默认值:3(新增于 3.4.5)
poolPingQuery – 发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。
poolPingEnabled – 是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。
poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。
properties(属性)
我们可以通过properties属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。
编写一个配置文件
driver = com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8/>
username=root
password=123456
在核心配置文件中引入
<properties resource="db.properties"/>
可以添加属性
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
来自官方文档
类型别名(typeAliases)
1、类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
使用之前 UserMapper.xml
<select id="getUserList" resultType="com.test.pojo.User">
<!--resultType返回一个结果,这里返回的时实体类User结果-->
select * from mybatis.user
</select>
使用之后
<select id="getUserList" resultType="User">
<!--resultType返回一个结果,这里返回的时实体类User结果-->
select * from mybatis.user
</select>
2、也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean
扫描实体类的包,它的默认别名就为这个类的名字,首字母大小写。(建议使用小写)
使用之前
<select id="getUserList" resultType="com.test.pojo.User">
<!--resultType返回一个结果,这里返回的时实体类User结果-->
select * from mybatis.user
</select>
使用
<typeAliases>
<package name="com.test.pojo"/>
</typeAliases>
使用之后
<select id="getUserList" resultType="user">
<!--resultType返回一个结果,这里返回的时实体类User结果-->
select * from mybatis.user
</select>
在实体类比较少的时候,使用第一种
如果实体类十分多,建议使用第二种
若有注解,则别名为其注解值
@Alias("author")
public class Author {
...
}
来自官方文档
设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
| cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
|---|---|---|---|
| lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 |
true | false | false |
| logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J(3.5.9 起废弃) | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
虽然很重但是spring之后就不用了 官方网址mybatis – MyBatis 3 | 配置
映射器(mappers)
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。
第一种方式:
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="com/test/dao/UserMapper.xml"/>
</mappers>
第二种方式:
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="com.test.dao.UserMapper"/>
</mappers>
第三种方式:
<!-- 将包内的映射器接口全部注册为映射器 -->
<mappers>
<package name="com.test.dao"/>
</mappers>
注意点:
接口和他的Mapper配置文件必须同名
接口和他的Mapper配置文件必须在同一个包下
4、入门
SqlSessionFactoryBuilder
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
构建 SqlSessionFactory
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
第一步:在mybatis-config.xml配置核心设置
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<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>
</configuration>
<!--environment 元素体中包含了事务管理和连接池的配置。-->
第二步创建SqlSessionFactory
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
//使用mybayis第一步获取SqlSessionFactory
static{
try {
//定位核心配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
从 SqlSessionFactory 中获取 SqlSession
在测试类中
public void test(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//获取写在mapper.xml中的sql语句
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
// List<User> userList = sqlSession.selectList("com.test.dao.UserDao");
for(User user:userList){
System.out.println(user);
}
sqlSession.close();
}
作用域(Scope)和生命周期
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
SqlSession
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:
try (SqlSession session = sqlSessionFactory.openSession()) {
// 你的应用逻辑代码
}
5、resultMap
<!--结果集映射-->
<resultMap id="UserMap" type="com.test.pojo.User">
<!--column数据库中的字段,property实体类中的字段-->
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<!--当数据库和实体类中的变量名不一致时使用,这里面column对应的是数据库的列名或别名;property对应的是结果集的字段或属性。-->
<select id="getUserList" resultMap="UserMap">
select * from mybatis.user
</select>
resultMap元素是 MyBatis 中最重要最强大的元素。- ResultMap的设计思想是,对于简单的语句根本不需要配置显示的结果映射,而对于复杂一点的语句只需要描述它们的关系就好了
- ResultMap最优秀的地方在于,你完全可以不用显式地配置它们
日志工厂
| logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J(3.5.9 起废弃) | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
|---|
标准日志:STDOUT_LOGGING
<settings>
<!--标准日志格式-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
LOG4J2:
依赖:
<!--log4j2日志实面-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.12.0</version>
</dependency>
<!--log4j2日志门面-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.12.0</version>
</dependency>
配置文件log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!-- log4j2 配置文件 -->
<!-- 日志级别 trace<debug<info<warn<error<fatal -->
<configuration status="info" >
<!-- 自定义属性 -->
<Properties>
<!-- 日志格式(控制台) -->
<Property name="pattern1">[%-5p] %d %c - %m%n</Property>
<!-- 日志格式(文件) -->
<Property name="pattern2">
====================================%n 日志级别:%p%n 日志时间:%d%n 所属类名:%c%n 所属线程:%t%n 日志信息:%m%n
</Property>
<!-- 日志文件路径 -->
<Property name="filePath">logs/myLog.log</Property>
</Properties>
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${pattern1}"/>
</Console>
<RollingFile name="RollingFile" fileName="${filePath}"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern="${pattern2}"/>
<SizeBasedTriggeringPolicy size="5 MB"/>
</RollingFile>
</appenders>
<loggers>
<root level="debug">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFile"/>
</root>
</loggers>
</configuration>
6、分页查询
UserMapper
//分页
List<User> getUserByLimit(Map<String,Integer> map);
UserMapper.xml
<select id="getUserByLimit" parameterType="map" resultType="User">
select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
UserDaoTest
@Test
public void getUserByLimit(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> map= new HashMap<String,Integer>();
map.put("startIndex",0);
map.put("pageSize",2);
List<User> userList= mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
7、注解开发
-
大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
-
根本原因:解耦,可拓展,提高复用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好
-
在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
-
而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程
关于接口的理解
-
接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
-
接口的本身反映了系统设计人员对系统的抽象理解。
-
接口应有两类:
第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);
第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface)
- 一个体有可能有多个抽象面。抽象体与抽象面是有区别的。
三个面向区别
-
面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法
-
面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现
-
接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题.更多的体现就是对系统整体的架构
8、使用注解开发
使用之前
在UserMapper接口写方法
User getUserById(int id);
在UserMapper.xml中写sql语句
<select id="getUserById" parameterType="int" resultType="User">
select * from mybatis.user where id = #{id};
</select>
使用注解之后
//根据id查询用户
@Select("select * from mybatis.user where id =#{id}")
User getUserById(int id);
不能两种方法一起使用,注解只使用简单的语句
使用注解的crud
@Insert("insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd})")
Integer addUser(User user);
@Delete("delete from mybatis.user where id = #{id};")
int deleteUser(int id);
@Select("select * from mybatis.user where id =#{id}")
User getUserById(@Param("id") int id);
@Update("update mybatis.user set name = #{name},pwd=#{pwd} where id = #{id}")
int updateUser(User user);
不用在xml文件中在写sql语句
关于@Param()注解
- 基本类型的参数或String类型,需要加上
- 引用类型不需要加
- 如果只有一个基本类型的话,可以忽略,但是建议大家都加上
- 我们在SQL中引用的就是我们这里的@Param()中设定的属性名
{} ${}区别
#{}是预编译处理,$ {}是字符串替换。
2)MyBatis在处理#{}时,会将SQL中的#{}替换为?号,使用PreparedStatement的set方法来赋值;MyBatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。
3)使用 #{} 可以有效的防止SQL注入,提高系统安全性。
尽量用#{}
9、Lombok
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java.
Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.
翻译
Project Lombok 是一个 Java 库,它会自动插入编辑器和构建工具,为您的 Java 增添趣味。
永远不要再写另一个 getter 或 equals 方法,使用一个注释,您的类有一个功能齐全的构建器,自动化您的日志记录变量等等。
依赖
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
在实体类上加@Data@AllArgsConstructor@NoArgsConstructor
@Data //get,set,toString方法
@AllArgsConstructor //有参
@NoArgsConstructor //无参
public class User {
private int id;
private String name;
private String pwd;
}
10、多表关联
多对一
- 按照查询嵌套处理
<mapper namespace="com.test.mapper.StudentMapper">
<!--
1、查询所有学生信息
2、根据查询出来的学生tid,寻找对应的老师
column对应的是数据库的列名或别名;property对应的是结果集的字段或属性
-->
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂的属性,我们需要单独处理
对象:association
集合:collection
-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id}
</select>
</mapper>
按照结果查询
<!--按照结果嵌套查询-->
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id,s.name sname,t.name tname
from student as s,teacher as t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
一对多
按结果嵌套处理
<!-- 按结果嵌套查询-->
<select id="getTeacher" resultMap="TeacherStudent">
SELECT s.id sid,s.name sname,t.name tname,t.id,tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!-- 复杂的属性,我们需要单独处理 对象:association 集合:collection
javaType="" 指定属性的类型!
集合中的泛型信息,我们使用ofType获取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
按照查询嵌套处理
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from mybatis.teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="Student">
select * from mybatis.student where tid = #{tid}
</select>
11、动态SQL
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
if
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果(细心的读者可能会发现,“title” 的参数值需要包含查找掩码或通配符字符)
choose
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG(这可能是管理员认为,与其返回大量的无意义随机 Blog,还不如返回一些由管理员精选的 Blog)。
where
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
WHERE
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</select>
如果没有匹配的条件会怎么样?最终这条 SQL 会变成这样:
SELECT * FROM BLOG
WHERE
这会导致查询失败。如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
这个查询也会失败。这个问题不能简单地用条件元素来解决。这个问题是如此的难以解决,以至于解决过的人不会再想碰到这种问题。
MyBatis 有一个简单且适合大多数场景的解决办法。而在其他场景中,可以对其进行自定义以符合需求。而这,只需要一处简单的改动:
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。**
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
set
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
对于set和where,你可以通过使用trim元素来达到同样的效果:
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<trim prefix="SET" suffixOverrides=",">
...
</trim>
sql片段
搭配使用
<sql id="if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
AND author = #{author}
</if>
</sql>
<select id="queryBlogIF" resultType="com.test.pojo.Blog">
select * from mybatis.blog
<where>
<include refid="if-title-author"/>
</where>
</select>
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:
<select id="queryBlogForeach" resultType="com.test.pojo.Blog">
<!---->
select * from mybatis.blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
@Test
public void queryBlogForeach(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(3);
map.put("ids",ids);
List<Blog> blogs = mapper.queryBlogForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
动态SQL就是在拼接SQL语句,我们要保证SQL的正确性,按照SQL的格式,去排列组合就可以了。
测试环境搭建
固定操作
1、建立MybatisUtils 工具类
2、建立db.properties文件
//测试类
SqlSession sqlSession = MyBatisUtils.getSqlSession();
接口 mapper = sqlSession.getMapper(接口.xml);
实体类 变量 = mapper.方法;
System.out.println(teacher);
sqlSession.close();
1、导入lombok
2、新建实体类
3、建立mapper
4、建立maper.xml文件
5、在核心配置文件中绑定注册我们的mapper接口或者文件
6、测试查询是否能够成功
浙公网安备 33010602011771号