MyBatis
环境:
- JDK1.8
- Mysql5.7
- maven3.6.1
- IDEA
1.什么是Mybatis
-
MyBatis 是一款优秀的持久层框架,
-
它支持自定义 SQL、存储过程以及高级映射。
-
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
-
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.1、获得Mybatis
-
Maven
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency>
-
github
2、Mybatis程序
2.1、mybatis核心配置文件(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-->
<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/school?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
//每一个mapper需要配置一份xml的路径
<mappers>
<mapper resource="UserMapper.xml"/>
<!--mapper...-->
</mappers>
</configuration>
2.2、maven配置文件(pom.xml)配置导出资源文件
否则可能会报错找不到UserMapper.xml文件
<!--导出资源文件-->
<!-- 资源目录 -->
<resources>
<resource>
<!-- 设定主资源目录 -->
<directory>src/main/java</directory>
<!-- maven default生命周期,process-resources阶段执行maven-resources-plugin插件的resources目标处理主资源目下的资源文件时,只处理如下配置中包含的资源类型 -->
<includes>
<include>**/*.xml</include>
</includes>
<!-- maven default生命周期,process-resources阶段执行maven-resources-plugin插件的resources目标处理主资源目下的资源文件时,不处理如下配置中包含的资源类型(剔除下如下配置中包含的资源类型)-->
<excludes>
<exclude>**/*.yaml</exclude>
</excludes>
<!-- maven default生命周期,process-resources阶段执行maven-resources-plugin插件的resources目标处理主资源目下的资源文件时,指定处理后的资源文件输出目录,默认是${build.outputDirectory}指定的目录-->
<!--<targetPath>${build.outputDirectory}</targetPath> -->
<!-- maven default生命周期,process-resources阶段执行maven-resources-plugin插件的resources目标处理主资源目下的资源文件时,是否对主资源目录开启资源过滤 -->
<filtering>true</filtering>
</resource>
</resources>
2.3、一个实体类的操作方式
每个mapper.xml都需要在mybatis核心配置文件中进行配置
<mappers>
<mapper resource="UserMapper.xml"/>
<!--mapper...-->
</mappers>
工具类
package utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.*;
import java.io.*;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static{
InputStream inputStream = null;
try {
String resource = "mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
实体类
package entity;
public class User {
private int id;
private String name;
private String pwd;
User(int id,String name,String pwd){
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int 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;
}
}
UserMapper.java接口
package dao;
import entity.User;
import java.util.List;
public interface UserMapper {
List<User> getAllUser();
//User selectById(int id);
//int deleteById(int id);
//int UpdateById(int id);
//int InsertUser(User user);
}
UserMapper.java的mapper配置文件
<?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="dao.UserMapper">
<select id="getAllUser" resultType="entity.User">
select * from user
</select>
</mapper>
测试类
package dao;
import entity.User;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import utils.MybatisUtils;
import java.util.List;
public class UserMapperTest {
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//方式一,getMapper 推荐使用方式一
UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
List<User> users1 = usermapper.getAllUser();
for (User user : users1) {
System.out.println(user.getName());
}
sqlSession.close();
//方式二,getMapper
List<User> users2 = sqlSession.selectList("dao.UserMapper.getAllUser");
for (User user : users2) {
System.out.println(user.getName());
}
sqlSession.close();
}
}
3、CRUD
增删改需要提交事务!
mapper接口类增加方法
package dao;
import entity.User;
import java.util.List;
public interface UserMapper {
List<User> getAllUser();
User selectById(int id);
int deleteById(int id);
int UpdateById(User user);
int InsertUser(User user);
}
3.1、select
<select id="getAllUser" resultType="entity.User">
select * from user
</select>
<select id="selectById" resultType="entity.User" parameterType="int">
select * from user where id = #{id}
</select>
- id:对应namespace绑定的接口中的方法名
- resultType:返回值类型
- parameterType:参数类型
3.2、 insert
<insert id="InsertUser" parameterType="entity.User">
insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>
测试代码
UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
int row = usermapper.InsertUser(new User(4,"zmy","pwd123"));
sqlSession.commit();//此处为提交事务的代码
System.out.println(row);
sqlSession.close();
3.3、update
<update id="UpdateById" parameterType="entity.User">
update user set name = #{name},pwd=#{pwd} where id = #{id}
</update>
测试代码
UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
int row = usermapper.UpdateById(new User(4,"zmy","pwdpwd123"));
sqlSession.commit();
System.out.println(row);
sqlSession.close();
3.4、delete
<delete id="deleteById" parameterType="int">
delete from user where id = #{id}
</delete>
测试代码
UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
int row = usermapper.deleteById(4);
sqlSession.commit();
System.out.println(row);
sqlSession.close();
4、配置解析
4.1.0、核心配置文件
mybatis-config.xml
4.1.1、environments和environment
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</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>
注意一些关键点:
- 默认使用的环境 ID(比如:default=“development”)。
- 每个 environment 元素定义的环境 ID(比如:id=“development”)。
- 事务管理器的配置(比如:type=“JDBC”)。
- 数据源的配置(比如:type=“POOLED”)。
默认环境和环境 ID 顾名思义。 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为
数据源(dataSource)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
- 大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")
4.1.2、mappers
方式一:相对路径
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
方式二:全路径,不推荐
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
方式三:接口扫描
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
注意点:
- xml和class同名
- xml和class同一个包下
方式四:包扫描
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
注意点:
- xml和class同名
- xml和class同一个包下
4.1.3、properties
使用${}进行取值
使用方式
<configuration>
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
<environments default="development">
<!--可以配置多个environment-->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--value对应properties标签中每一个property的name-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
db.properties文件内容如下
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/school
user=root
password=123456
- 可以直接引入外部配置文件
- 可以在properties标签中property使用增加一些字段
- 如果文件中和property标签有同样名字的字段,有限使用配置文件的
4.1.4、typeAliases(别名)
方式一:配置一个实体类的别名
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
</typeAliases>
方式二:扫描包
<typeAliases>
<package name="dao"/>
</typeAliases>
每一个在包中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author
的别名为 author
;若有注解,则别名为其注解值。看下面的例子:
@Alias("author")
public class Author {
...
}
4.1.5、settings(设置)
设置参数 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 该配置影响的所有映射器中配置的缓存的全局开关。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType 属性来覆盖该项的开关状态。 | true | false | false |
aggressiveLazyLoading | When enabled, any method call will load all the lazy properties of the object. Otherwise, each property is loaded on demand (see also lazyLoadTriggerMethods ). | true | false | false (true in ≤3.4.1) |
multipleResultSetsEnabled | 是否允许单一语句返回多结果集(需要兼容驱动)。 | true | false | true |
useColumnLabel | 使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。 | true | false | true |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 | true | false | False |
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL |
autoMappingUnknownColumnBehavior | Specify the behavior when detects an unknown column (or unknown property type) of automatic mapping target. NONE : Do nothing WARNING : Output warning log (The log level of 'org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' must be set to WARN ) FAILING : Fail mapping (Throw SqlSessionException ) | NONE, WARNING, FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库响应的秒数。 | 任意正整数 | Not Set (null) |
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | Not Set (null) |
safeRowBoundsEnabled | 允许在嵌套语句中使用分页(RowBounds)。 If allow, set the false. | true | false | False |
safeResultHandlerEnabled | 允许在嵌套语句中使用分页(ResultHandler)。 If allow, set the false. | true | false | True |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true | false | False |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。 | SESSION | STATEMENT | SESSION |
jdbcTypeForNull | 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 | JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER | OTHER |
lazyLoadTriggerMethods | 指定哪个对象的方法触发一次延迟加载。 | A method name list separated by commas | equals,clone,hashCode,toString |
defaultScriptingLanguage | 指定动态 SQL 生成的默认语言。 | A type alias or fully qualified class name. | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
callSettersOnNulls | 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。 | true | false | false |
returnInstanceForEmptyRow | MyBatis, by default, returns null when all the columns of a returned row are NULL. When this setting is enabled, MyBatis returns an empty instance instead. Note that it is also applied to nested results (i.e. collectioin and association). Since: 3.4.2 | true | false | false |
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | Any String | Not set |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | Not set |
proxyFactory | 指定 Mybatis 创建具有延迟加载能力的对象所用到的代理工具。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 or above) |
vfsImpl | 指定VFS的实现 | 自定义VFS的实现的类全限定名,以逗号分隔。 | Not set |
useActualParamName | 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的工程必须采用Java 8编译,并且加上-parameters 选项。(从3.4.1开始) | true | false | true |
一个完整的设置如下:
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
4.1.6、生命周期和作用域
错误地使用生命周期和作用域会导致并发问题
SqlSessionFactoryBuilder
- 一旦创建了SqlSessionFactory,就不再需要了
- 局部变量
SqlSessionFactory
- 一旦创建,就应该在应用运行期间一直存在。重复创建会导致资源浪费。
- 应用作用域
- 使用单例模式或者静态单例模式
SqlSession
- SqlSession不是线程安全的
- 方法作用域,用完即关闭
5、ResultMap
解决数据库字段和实体类属性名称不一致的问题
<resultMap id = "UserMap" type = "User">
<!--
column : 数据库字段
property : 实体类属性
-->
<result column="pwd" property="password"/>
</resultMap>resultMap>
<select id="selectById" resultMap="UserMap" parameterType="int">
select * from user where id = #{id}
</select>
6、日志
通过settings标签设置日志
日志的实现类有如下几种:SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
<configuration>
<settings>
<!--STDOUT_LOGGING为标准日志输出-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
7、Log4j
- Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
- 我们也可以控制每一条日志的输出格式;
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
- 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
7.1、导入Log4j的jar包
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
7.2、日志文件log4j.properties放在resources文件夹下,内容如下:
#将等级为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/kuang.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
7.3、配置Log4j日志
<configuration>
<settings>
<!--STDOUT_LOGGING为标准日志输出-->
<setting name="logImpl" value="LOG4J"/>
</settings>
</configuration>
7.4、使用Log4j
package dao;
import org.apache.log4j.Logger;
import org.junit.Test;
public class UserMapperTest {
private Logger logger = Logger.getLogger(UserMapperTest.class);
@Test
public void test(){
logger.debug("debug:进入test");
logger.info("info:进入test");
logger.error("error:进入test");
}
}
效果如下:
8、分页
8.1、使用limit分页
1、接口
List<User> getUserByLimit(Map<String,Integer> map);
2、mapper.xml
<select id="getUserByLimit" resultType="entity.User" parameterType="map">
select * from user limit #{startIndex},#{pageSize}
</select>
3、测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//方式一,getMapper 推荐使用方式一
UserMapper usermapper = sqlSession.getMapper(UserMapper.class);
Map<String,Integer> map = new HashMap<String,Integer>();
map.put("startIndex",1);
map.put("pageSize",2);
List<User> users1 = usermapper.getUserByLimit(map);
for (User user : users1) {
System.out.println(user);
}
sqlSession.close();
}
8.2、使用RowBounds分页
1、接口
List<User> getUserByRowbounds();
2、mapper.xml
<select id="getUserByRowbounds" resultType="entity.User">
select * from user
</select>
3、测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
RowBounds rowBounds = new RowBounds(1, 2);
List<User> users1 = sqlSession.selectList("dao.UserMapper.getUserByRowbounds",null,rowBounds);
for (User user : users1) {
System.out.println(user);
}
sqlSession.close();
}
9、使用注解开发
使用注解开发可以省略掉mapper.xml配置文件。但是在核心配置文件mybatis-config.xml中,需要通过绑定接口的方式来绑定mapper
mybatis-config.xml文件内容如下:
<mappers>
<!--<mapper resource="dao/UserMapper.xml"/>-->
<mapper class="dao.UserMapper"/>
</mappers>
接口:
@Select("select * from user where id = #{id} and name = #{name}")
User selectById(@Param("id")int id,@Param("name")String name);
测试:
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.selectById(1,"张三");
System.out.println(user);
sqlSession.close();
}
@Param
- 当只有一个基本类型的参数时,可省略
- 当参数不止一个时,必须有
- #{}中使用@Param指定的名字
#{} 和 ${}的区别:
-
#{}可以防止sql注入,推荐使用
-
${}不能防止sql注入
10、多对一的处理
mapper.xml配置文件,使用association标签
<select id="getStudent" resultMap="StudentTeacher">
select s.id as sid,s.name as sname,t.id as tid,t.name as tname from student s,teacher t where s.tid = t.id
</select>
<resultMap id="StudentTeacher" type="student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
接口StudentMapper.java
List<Student> getStudent();
实体类
package entity;
public class Student {
private int id;
private String name;
private Teacher teacher;
public Student(int id, String name, Teacher teacher) {
this.id = id;
this.name = name;
this.teacher = teacher;
}
...
}
package entity;
public class Teacher {
private int id;
private String name;
public Teacher() {
}
public Teacher(int id, String name) {
this.id = id;
this.name = name;
}
...
}
测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent();
for (Student student : studentList) {
System.out.println(student);
}
sqlSession.close();
}
11、一对多的处理
mapper.xml配置文件,使用collection标签
<select id="getTeacher" resultMap="TeacherStudent">
select t.id as tid,t.name as tname,s.name as sname,s.id as sid,s.tid as stid from teacher t,student s where t.id = s.tid
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="student">
<result property="name" column="sname"/>
<result property="id" column="sid"/>
<result property="tid" column="stid"/>
</collection>
</resultMap>
接口TeacherMapper.java
List<Teacher> getTeacher();
实体类
package entity;
import java.util.List;
public class Teacher {
private int id;
private String name;
private List<Student> students;
...
}
package entity;
public class Student {
private int id;
private String name;
private int tid;
public Student() {
}
public Student(int id, String name, int tid) {
this.id = id;
this.name = name;
this.tid = tid;
}
...
}
测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
List<Teacher> teacherList = mapper.getTeacher();
for (Teacher teacher : teacherList) {
System.out.println(teacher);
}
sqlSession.close();
}
12、动态SQL
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
12.1、IF
<select id="findActiveBlogWithTitleLike" resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<if test="title != null">
<!--title是*中的一个字段-->
AND title like #{title}
</if>
</select>
12.2、choose、when、otherwise
<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>
12.3、trim、where、set
<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>
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<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>
12.4、foreach
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>