相关PDF版资料已同步微信公众号
乐享Coding
欢迎你的关注,二维码在文章底部,获取最全Java学习资料和相关电子书!
Mybatis框架
ORMapping:对象关系映射
关系指关系型数据库的映射
Java到MySQL的映射,开发者可以以面向对象的思想进行开发。
优点
- 封装JDBC,减少代码量
- SQL写在XML文件里,降低耦合度,便于统一管理和优化,并可重用。
- 提供XML标签,支持编写动态SQL语句
- 提供映射标签,支持对象与数据库的ORM字段关系映射。
缺点
- SQL语句编写工作量较大,尤其是字段多,关联表多时,更是复杂。
- SQL语句依赖数据库,不同数据库SQL语句存在细微差异,不能随意更换数据库。
开发方式
- 原生接口
- Mapper代理实现自定义接口
初步使用
导入依赖
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</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.16</version>
</dependency>
- 创建t_account表
CREATE TABLE t_account(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(11) ,
pwd VARCHAR(11),
age INT
)
- 创建实体类Account进行映射
@Data
public class Account {
private Integer id;
private String username;
private String pwd;
private Integer age;
}
- 全局配置核心文件SqlMapperConfig.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>
<!--配置mybatis运行环境-->
<environments default="development">
<environment id="development">
<!--配置jdbc事务管理-->
<transactionManager type="JDBC"/>
<!--配置JDBC数据源连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatisExercise?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="77549252"/>
</dataSource>
</environment>
</environments>
</configuration>
使用原生接口
1.Mybatis框架需要开发者自定义SQL语句,写在Mapper.xml文件中,实际开发中,会为每个实体类创建对应的Mapper.xml,定义管理该对象数据的SQL。
- namespace通常设置为文件所在包+文件名的形式。
- insert标签表示执行添加操作
- select标签表示执行查询操作
- update标签表示执行更新操作
- delete标签表示执行删除操作
- id是实际调用Mybatis方法时需要用到的参数。
- parameterType是调用对应方法时参数的数据类型
<?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.Long.Mapper.XML.AccountMapper">
<!-- <select id=""></select>-->
<insert id="add" parameterType="com.Long.Entity.Account">
insert into t_account(username,pwd,age) values (#{username},#{pwd},#{age});
</insert>
<!-- <delete id=""></delete>-->
<!-- <update id=""></update>-->
</mapper>
2.AccountMapper.xml注册到全局配置核心文件SqlMapperConfig.xml文件中
<!--注册AccountMapper.xml-->
<mappers>
<!--这里路径用/-->
<mapper resource="com/Long/Mapper/XML/AccountMapper.xml"></mapper>
</mappers>
3.pom.xml配置java目录下的xml文件生效,默认只是resource目录下xml文件生效
<!--配置java目录下xml文件生效-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
4.测试
public class testMybatis {
public static void main(String[] args) {
//加载Mybatis配置文件
InputStream InputStream = testMybatis.class.getClassLoader().getResourceAsStream("SqlMapperConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory Factory = sqlSessionFactoryBuilder.build(InputStream);
SqlSession sqlSession = Factory.openSession();
String statement="com.Long.Mapper.XML.AccountMapper.add";
Account account =new Account(1,"张三","123456",18);
//提交事务
sqlSession.commit(); //查询不需要,增删改必须提交
//关闭连接池
sqlSession.close();
}
}
通过Mapper代理实现自定义接口(重要)
-
自定义Mapper接口
public interface AccountMapper { int add(Account account); int update(Account account); int deleteById(Integer id); List<Account> findAll(); Account findById(Integer id); }
2.创建对应的Mapper.xml,定义接口方法对应的SQL语句。
标签可选insert,delete,update,select。
Mybatis框架会根据规则自动创建接口实现类的代理对象。(代理的是接口,代理对象为实现类)
映射规则
:
- namespace属性值为接口的全类名。
- id属性为接口中对应的方法名。
- parameterType属性值和接口中对应方法传递的参数类型一致。
- resultType属性值和接口中对应方法返回值类型一致(只有查用写,增删改都是返回int)。
@Test
public void test2() {
InputStream InputStream = testMybatis.class.getClassLoader().getResourceAsStream("SqlMapperConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory Factory = sqlSessionFactoryBuilder.build(InputStream);
SqlSession sqlSession = Factory.openSession();
//获取实现接口的代理对象
AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
//增
Account account1 = new Account(1,"小风","14525",18);
mapper.add(account1);
sqlSession.commit();
//查
List<Account> accountList = mapper.findAll();
for (Account account:accountList
) {
System.out.println(account);
}
//删
mapper.deleteById(1);
sqlSession.commit();
//查
System.out.println(mapper.findById(2));
//改
Account account2 = new Account(3, "小雨", "145256", 18);
mapper.update(account2);
sqlSession.commit();
//关闭连接池
sqlSession.close();
}
总结
先解析resource文件夹下Config.xml文件配置的环境(如何连接数据库)和注册的mapper.xml文件。
Mapper.xml文件配置实体类(JavaBean)属性与数据库字段如何进行映射。
级联查询
class表
student表
Java实体类映射【Student】和【Classes】
@Data
public class Student {
private Integer id;
private String name;
private Classes classes;
}
@Data
public class Classes {
private Integer id;
private String name;
private List<Student> students;
}
连接查询
一对一
连接student表和class表,查询id为1的学生(包含所在班级名称)
SQL语句
select * from student s,class c where s.cid=c.id and s.id =1;
xml配置文件
<mapper namespace="com.Long.Mapper.StudentMapper">
<resultMap id="studentMap" type="com.Long.Entity.Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<association property="classes" javaType="com.Long.Entity.Classes">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</association>
</resultMap>
<select id="findByIdAndClass" parameterType="Integer" resultMap="studentMap">
select s.id,s.name,c.id as cid,c.name as cname from student s,class c where s.id = #{id} and s.cid = c.id
</select>
总结
查询操作返回值映射
resultType属性
- 直接映射,即根据数据库字段名称和Java对象属性名称和类型一一映射,
resultmap属性
- 根据column属性(数据库字段名称)和property属性(Java对象属性名)进行名称映射的。
- id标签是主键,result标签是普通字段
- 包含多个字段的java对象需要association标签
- 包含多个字段的java集合需要association标签
一对多
连接student表和class表,查询id为2的班级中所有学生信息
SQL语句
select s.id,s.name ,c.id,c.name from student s,class c where c.id =2 and s.cid = c.id
xml配置文件
<mapper namespace="com.Long.Mapper.StudentMapper">
<resultMap id="studentMap" type="com.Long.Entity.Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<association property="classes" javaType="com.Long.Entity.Classes">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</association>
</resultMap>
<select id="findByIdAndClass" parameterType="Integer" resultMap="studentMap">
select s.id,s.name ,c.id,c.name from student s,class c where s.id = #{id} and s.cid = c.id;
</select>
测试
@Test
public void test3() {
InputStream InputStream = Student.class.getClassLoader().getResourceAsStream("SqlMapperConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory Factory = sqlSessionFactoryBuilder.build(InputStream);
SqlSession sqlSession = Factory.openSession();
//获取实现接口的代理对象
ClassesMapper mapper = sqlSession.getMapper(ClassesMapper.class);
System.out.println(mapper.findStudentsByClassId(2)); //返回的集合不用for循环遍历
sqlSession.close();
}
多对多(一对多的升级)
逆向工程(代码自动生成)
传统的开发中上述的三个组件需要开发者手动创建,逆向工程可以帮助开发者来自动创建三个组件,减
轻开发者的工作量,提高工作效率。
MyBatis 框架需要(三个组件):
- 实体类
- 自定义 Mapper 接口
- Mapper.xml
MyBatis Generator,简称 MBG,是⼀个专门为 MyBatis 框架开发者定制的代码⽣成器,可自动生成
MyBatis 框架所需上述三组件,也可支持基本的 CRUD 操作,但是⼀些相对复杂的 SQL 需要开发者自己来完成。
相关jar包
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
创建 MBG 配置文件 config.xml
1、jdbcConnection 配置数据库连接信息。
2、javaModelGenerator 配置 JavaBean 的生成策略。
3、sqlMapGenerator 配置 SQL 映射文件生成策略。
4、javaClientGenerator 配置 Mapper 接口的生成策略。
5、table 配置目标数据表(tableName:表名,domainObjectName:JavaBean 类名)。
resouce目录下的config.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<jdbcConnection
driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatisExercise?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"
userId="root"
password="77549252"
/>
<javaModelGenerator targetPackage="com.Long.Entity"
targetProject="Genertor/src/main/java"/>
<sqlMapGenerator targetPackage="com.Long.Mapper.XML"
targetProject="Genertor/src/main/java"/>
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.Long.Mapper" targetProject="Genertor/src/main/java">
</javaClientGenerator>
<table tableName="t_account" domainObjectName="Account"/>
</context>
</generatorConfiguration>
Genertor类测试
public class Genertor {
public static void main(String[] args) {
List<String> warings = new ArrayList<String>();
boolean overwrite = true;
String genCig = "/config.xml";
File configFile = new File(Genertor.class.getResource(genCig).getFile());
ConfigurationParser configurationParser = new
ConfigurationParser(warings);
Configuration configuration = null;
try {
configuration = configurationParser.parseConfiguration(configFile);
} catch (IOException e) {
e.printStackTrace();
} catch (XMLParserException e) {
e.printStackTrace();
}
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = null;
try {
myBatisGenerator = new
MyBatisGenerator(configuration, callback, warings);
} catch (InvalidConfigurationException e) {
e.printStackTrace();
}
try {
myBatisGenerator.generate(null);
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
目录结构
延迟加载 (懒加载)
延迟加载也叫懒加载、惰性加载,使⽤延迟加载可以提高程序的运行效率,针对于数据持久层的操左, 在某些特定的情况下去访问特定的数据库,在其他情况下可以不访问某些表,从⼀定程度上减少了 Java 应用与数据库的交互次数。
查询学生和班级的时,学生和班级是两张不同的表,如果当前需求只需要获取学生的信息,那么查询学生单表即可。
如果需要通过学生获取对应的班级信息,则必须查询两张表。
不同的业务需求,需要查询不同的表,根据具体的业务需求来动态减少数据表查询的工作就是延迟加载。
之前查询任务实现懒加载
连接student表和class表,查询id为1的学生(包含所在班级名称)
select * from student s,class c where s.cid=c.id and s.id =1;
-
拆分成两条SQL语句
-
select * from student where id =1;
当需要班级信息时,需要执行下面SQL语句,id参数为第一条语句查询到的cid
select * from class where id =#{id};
-
懒加载目的:不需要获取班级信息的需求时不需要执行第二条sql语句,增加效率,根据需求可以动态改变。
resouce目录下的config.xml配置文件配置懒加载
<settings> <!-- 打印SQL--> <setting name="logImpl" value="STDOUT_LOGGING" /> <!-- 开启延迟加载 --> <setting name="lazyLoadingEnabled" value="true"/> </settings>
-
StudentMapper接口和ClassesMapper接口各定义查找方法
// ClassesMapper接口 public interface ClassesMapper { Classes findById(Integer id); }
public interface StudentMapper { Student findById(Integer id); }
-
配置文件配置两条SQL语句的关系
StudentMapper.xml文件下配置
<mapper namespace="com.Long.Mapper.StudentMapper"> <resultMap id="studentMap" type="com.Long.Entity.Student"> <id column="id" property="id"/> <result column="name" property="name"/> <collection property="classes" javaType="com.Long.Entity.Classes" select="com.Long.Mapper.ClassesMapper.findById" column="cid"/> </resultMap> <select id="findById" parameterType="Integer" resultMap="studentMap"> select * from student where id =#{id}; </select> </mapper>
ClassesMapper.xml文件下配置
<mapper namespace="com.Long.Mapper.ClassesMapper"> <select id="findById" parameterType="Integer" resultType="com.Long.Entity.Classes"> select * from class where id =#{id}; </select> </mapper>
-
测试
@Test public void test3() { InputStream InputStream = test.class.getClassLoader().getResourceAsStream("SqlMapperConfig.xml"); SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); SqlSessionFactory Factory = sqlSessionFactoryBuilder.build(InputStream); SqlSession sqlSession = Factory.openSession(); StudentMapper StudentMapper = sqlSession.getMapper(StudentMapper.class); Student student = StudentMapper.findById(1); System.out.println(student.getName()); //懒加载下不需要加载班级信息,执行1条SQL语句 // System.out.println(student.getClasses()); //懒加载下需要加载班级信息,执行2条SQL语句 sqlSession.close(); }
缓存
使用缓存可以减少 Java 应用与数据库的交互次数,从而提升程序的运行效率。比如查询出 id = 1 的对
象,第⼀次查询出之后会⾃动将该对象保存到缓存中,当下⼀次查询时,直接从缓存中取出对象即可,
无需再次访问数据库。
分类
1、⼀级缓存:SqlSession 级别,默认开启,并且不能关闭。
操作数据库时需要创建SqlSession对象,在对象中有⼀个HashMap用于存储缓存数据,不同的SqlSession 之间缓存数据区域是互不影响的。
⼀级缓存的作用域是SqlSession范围的,当在同⼀个SqlSession中执行两次相同的 SQL 语句事,第⼀次执行完毕会将结果保存到缓存中,第二次查询时直接从缓存中获取。
需要注意的是,如果SqlSession执行了 DML 操作(insert、update、delete),MyBatis 必须将缓存清空以保证数据的准确性。
验证
- 不同的SqlSession
@Test
public void test4() {
InputStream InputStream = test.class.getClassLoader().getResourceAsStream("SqlMapperConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory Factory = sqlSessionFactoryBuilder.build(InputStream);
SqlSession sqlSession = Factory.openSession();
StudentMapper StudentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = StudentMapper.findById(1);
System.out.println(student.getName());
sqlSession.close();
SqlSession sqlSession1 = Factory.openSession(); //创建不同的SqlSession
StudentMapper StudentMapper1 = sqlSession1.getMapper(StudentMapper.class);
Student student1 = StudentMapper1.findById(1);
System.out.println(student1.getName());
sqlSession1.close();
}
- 同一SqlSession
@Test
public void test4() {
InputStream InputStream = test.class.getClassLoader().getResourceAsStream("SqlMapperConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory Factory = sqlSessionFactoryBuilder.build(InputStream);
SqlSession sqlSession = Factory.openSession();
StudentMapper StudentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = StudentMapper.findById(1);
Student student1 = StudentMapper.findById(1);
System.out.println(student.getName());
System.out.println(student1.getName());
sqlSession.close();
}
2、二级缓存:Mapper级别,默认关闭,可以开启。
- 使用二级缓存时,多个SqlSession使用同⼀个Mapper的 SQL 语句操作数据库,得到的数据会存在二级缓存区。
- 同样是使用HashMap进行数据存储,相比较于⼀级缓存,二级缓存的范围更大,多个SqlSession 可以共用二级缓存,
- 二级缓存是跨SqlSession的。
二级缓存是多个 SqlSession 共享的,其作用域是Mapper的
同⼀个namespace
,不同的SqlSession两次执行相同的 namespace 下的 SQL 语句,参数也相等,则第⼀次执行成功之后会将数据保存到二级缓存中,第二次可直接从二级缓存中取出数据。
Mybatis自带二级缓存
-
Resource目录下的config.xml文件配置
<!-- 开启⼆级缓存 --> <setting name="cacheEnabled" value="true"/>
-
Mapper.xml配置
<cache/>
-
Entity包下的实体类实现序列化接口
@Data public class Student implements Serializable { private Integer id; private String name; private Classes classes; }
验证
@Test
public void test4() {
InputStream InputStream = test.class.getClassLoader().getResourceAsStream("SqlMapperConfig.xml");
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory Factory = sqlSessionFactoryBuilder.build(InputStream);
SqlSession sqlSession = Factory.openSession();
StudentMapper StudentMapper = sqlSession.getMapper(StudentMapper.class);
Student student = StudentMapper.findById(1);
System.out.println(student.getName());
sqlSession.close();
SqlSession sqlSession1 = Factory.openSession(); //创建不同的SqlSession
StudentMapper StudentMapper1 = sqlSession1.getMapper(StudentMapper.class);
Student student1 = StudentMapper1.findById(1);
System.out.println(student1.getName());
sqlSession1.close();
}
ehcache二级缓存
-
pom.xml导入相关jar包
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.4.3</version> </dependency>
-
添加Resource目录下的ehcache.xml,配置相关配置。
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <diskStore/> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
-
Resource目录下的config.xml文件配置
<!-- 开启⼆级缓存 --> <setting name="cacheEnabled" value="true"/>
-
Mapper.xml配置缓存策略
<cache type="org.mybatis.caches.ehcache.EhcacheCache"> <!-- 缓存创建之后,最后⼀次访问缓存的时间至缓存失效的时间间隔 --> <property name="timeToIdleSeconds" value="3600"/> <!-- 缓存⾃创建时间起⾄失效的时间间隔 --> <property name="timeToLiveSeconds" value="3600"/> <!-- 缓存回收策略,LRU表示移除近期使⽤最少的对象 --> <property name="memoryStoreEvictionPolicy" value="LRU"/> </cache>
-
Entity包下的实体类不需要实现序列化接口
@Data public class Student { private Integer id; private String name; private Classes classes; }
动态SQL标签
使用动态SQL可简化代码的开发,减少开发者的工作量,程序可以自动根据业务参数来决定SQL的组成。
AccountMapper AccountMapper = sqlSession.getMapper(AccountMapper.class);
Account account = new Account(1,"小明","123",22);
System.out.println(AccountMapper.findByAccount(account));
Account accountOne = new Account("小明","123");
System.out.println(AccountMapper.findByAccount(accountOne));
<!--动态执行该SQL语句,当需要根据id和username查时不需要额外的语句-->
<select id="findByAccount" parameterType="com.Long.Entity.Account" resultType="com.Long.Entity.Account">
select * from t_account where id =#{id} and username =#{username} and pwd=#{pwd} and age =#{age};
</select>
上述代码无动态SQL语句时,当只知道账户姓名和密码时确匹配失败,原因在于SQL语句多余传了默认值。
if 标签
if 标签可以自动根据表达式的结果来决定是否将对应的语句添加到 SQL 中,如果条件不成立则不添加, 如果条件成立则添加。
where 标签 (和if标签连用)
注意:where 标签不会检测SQL语句末尾多余的and并删除,因此and写在前面
where 标签可以自动判断是否要删除语句块中的 and 关键字,如果检测到 where 直接跟 and 拼接,则自动删除 and,通常情况下 if 和 where 结合起来使用。
<select id="findByAccount" parameterType="com.Long.Entity.Account" resultType="com.Long.Entity.Account">
select * from t_account
<where>
<if test="id!=null">
id =#{id}
</if>
<if test="username!=null">
and username =#{username}
</if>
<if test="pwd!=null">
and pwd=#{pwd}
</if>
<if test="age!=null">
and age =#{age}
</if>
</where>
</select>
choose 、when 、otherwise 标签
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。choose执行过程中按顺序判断 when 中的条件出否成立,如果有一个成立,则 choose 结束。当 choose 中所有 when的条件都不满则时,则执行 otherwise 中的 sql。
<!--动态执行该SQL语句,当需要根据id和username查时不需要额外的语句-->
<select id="findByAccount" parameterType="com.Long.Entity.Account" resultType="com.Long.Entity.Account">
select * from t_account
<where>
<choose>
<when test="id!=null">
id =#{id}
</when>
<when test="username!=null">
and username =#{username}
</when>
<when test="pwd!=null">
and pwd=#{pwd}
</when>
<when test="age!=null">
and age =#{age}
</when>
<otherwise>
<!--如果传入参数都为null那么就返回id=1的数据-->
id = 1
</otherwise>
</choose>
</where>
</select>
trim 标签
trim 标签中的 prefix 和 suffix 属性会被用于生成实际的 SQL 语句,会和标签内部的语句进行拼接,如果语句前后出现了 prefixOverrides或者suffixOverrides 属性中指定的值,MyBatis 框架会自动将其删除。
用trim标签实现where标签的作用
<!--where后面发现紧跟着and就自动删除-->
<trim prefix="where" prefixOverrides="and">
set 标签
set 标签用于 update 操作,会自动根据参数选择生成 SQL 语句。
静态更新SQL的问题
Account account = new Account(1,"小明","123",22);
System.out.println(AccountMapper.findByAccount(account));
account.setAge(18); //仅更改了年龄但SQL语句中其他属性进行了重复赋值
AccountMapper.update(account);
System.out.println(account);
<mapper namespace="com.Long.Mapper.AccountMapper">
<update id="update" parameterType="com.Long.Entity.Account">
update t_account set age=#{age},username =#{username},pwd=#{pwd} where id =#{id}
</update>
增加set标签
<mapper namespace="com.Long.Mapper.AccountMapper">
<update id="update" parameterType="com.Long.Entity.Account">
update t_account
<set>
<choose>
<when test="username!=null">
and username =#{username}
</when>
<when test="pwd!=null">
and pwd=#{pwd}
</when>
<when test="age!=null">
and age =#{age}
</when>
</choose>
</set>
where id = #{id}
</update>
foreach 标签
foreach 标签可以迭代生成⼀系列值,这个标签主要用于 SQL 的 in 语句。
举例
仅查询id=1,2,4的账户信息
静态SQL语句
select * from t_account where id in(1,2,4);
动态SQL(字符串拼接)
<select id="findByIds" parameterType="com.Long.Entity.Account" resultType="com.Long.Entity.Account">
select * from t_account
<where>
<foreach collection="ids" open="id in (" close=")" item="id"
separator=",">
#{id}
</foreach>
</where>
</select>
测试
ArrayList<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
ids.add(4);
Account account = new Account();
account.setIds(ids);
System.out.println(AccountMapper.findByIds(account));