一.Mybatis与其他持久层框架的对比:
从最基本的数据库连接框架JDBC说起,JDBC大致五步:编写sql、预编译、设置参数、执行sql、封装结果。JDBC的特点就是功能简单,但sql语句编写在java代码里,是一种硬编码高耦合的方式。
对于Hibernte来说,相当于把这5步进行了自动化,消除sql,对于开发者来说相当于黑箱操作,不需要学会JDBC以及Sql操作,只需要把javaBean对象和数据库表的关系处理好就行,但是省心的同时,所有大型项目最后都要牵扯定制Sql,优化Sql,最终要把Sql交给开发人员来写,不要让框架自动生成Sql
所以综合起来,你希望尽可能手动的去实现Sql的部分,又可以利用框架自动化的特点实现其他部分,Mybatis就是这样,将编写Sql这一步提取出来以XML配置文件的形式让开发者自己配置,其他的4步自动完成。特点:Sql与Java代码分离,Sql是开发人员控制,感觉算个半自动框架吧。
二.Mybatis创建步骤:
1.通过maven选择quickstart模板直接创建一个模板,会自带一个pom.xml文件
2.在pom.xml文件中引入两个依赖,一个MySql的,一个Mybatis的
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<!--mybatis配置-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
3.创建全局配置文件:在main包下创建一个resources包,并且右键选择Mark Directory as选项中的Resources Root选项,设置好后在此包下创建一个Mybatis-config.xml文件
4.配置全局配置文件:
<?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.jdbc.Driver"/> //mysql中的存储引擎
<property name="url" value="jdbc:mysql://localhost:3306/test"/> //mysql中的url
<property name="username" value="root"/> //用户名
<property name="password" value="123456"/> //密码
</dataSource>
</environment>
</environments>
</configuration>
官网上的示例标签
补充一个知识点:XML文件为可扩展性标记语言,XML是数据交换的公共语言,不同软件,不同操作系统都可以通过加载XML来进行数据的交换,在我们用到的Mybatis框架中,XML文件是通过识别各种各样的标签来进行的,但是前提是标签头你得先指定好,它才能去寻找相应的标签,你可以从Mybatis官网的示例文件中找到这个标签即mybatis-3-config.dtd
5.创建POJO类(即普通的java对象里面包含一些get和set方法),在com包的最底层即与maven加载的APP类在同一层创建此pojo实体类,里面包含数据库字段(此时字段声明均用其包装类类型),以及get和set方法,有必要的话还要包含toString和其他方法
6.定义mapper接口文件,在此层次上创建刚才POJO类的mapper接口,命名就为XxxMapper,里面写你的业务需求方法,比如通过学号来查询学生
public interface StudentMapper {
/**
* 通过SID查询数据实体
* @param sid
* @return
*/
public Student selectStudentByID(int sid);
}
7.配置Mapper文件:在刚才第三步的Resources包下创建一个mapper包,其下再创建一个StudentMapper.xml文件,引入相关约束:
<?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命令空间,随便写,一般保证命名空间唯一 -->
<mapper namespace="com.tulun.MybatisDemo.StudentMapper">
<!--查询标签:select-->
<select id="selectStudentByID" resultType="com.tulun.MybatisDemo.Student">
select * from Student where SID = #{sid}
</select>
</mapper>
这里的重点在于此XML的文件名必须和第6步中的POJO类的接口名保持一致,select id后面跟的字段必须跟POJO类的接口中的方法名保持一致,返回类型resultType即为POJO的实体类,这里用路径代替,然后就可以把你的查询SQl语句写在这个select标签中了,这里的SQL语句要使用占位符的形式
8.将Mapper配置文件引入到全局配置文件中,即修改全局配置文件Mybatis-config.xml
增加一个标签,引入其路径
<!--配置映射-->
<mappers>
<mapper resource="mapper/StudentMapper.xml"/>
</mappers>
9.创建执行类去执行操作
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 MybatisTLDemo {
public static void main(String[] args) throws IOException {
//mybatis配置文件
String resource = "mybatis-config.xml";
//通过mybatis提供的Resources类来得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂,传输mybatis配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过反射机制来获取对应mapper实例
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//调用mapper实例下方法
Student student = mapper.selectStudentByID(1);
System.out.println(student);
}
}
三.日志引入
1.先引入日志的依赖,当然是在最初始的通过maven快速加载出的pom.xml文件中
<!--log4j日志文件-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.创建resources包下创建名为log4j.properties的普通文件(非XML)
## debug 级别
log4j.rootLogger=DEBUG,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout = org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd-HH\:mm\:ss,SSS} [%t] [%c] [%p] - %m%n
log4j.logger.com.mybatis=DEBUG /
##输出sql 语句
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
这里的示例是debug级别的,当然还有其他级别的,这样的话再运行执行操作就会打印出相关的时间,哪个类用到了哪些配置文件等等
eg:
2020-05-10-09:18:42,188 [main] [org.apache.ibatis.transaction.jdbc.JdbcTransaction] [DEBUG] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@6adede5]
2020-05-10-09:18:42,191 [main] [com.tulun.MybatisDemo.StudentMapper.selectStudentByID] [DEBUG] - ==> Preparing: select * from Student where SID = ?
2020-05-10-09:18:42,351 [main] [com.tulun.MybatisDemo.StudentMapper.selectStudentByID] [DEBUG] - ==> Parameters: 1(Integer)
2020-05-10-09:18:42,372 [main] [com.tulun.MybatisDemo.StudentMapper.selectStudentByID] [DEBUG] - <== Total: 1
四.全局配置文件:mybatis-config.xml详解
所有介绍的标签都得写在根标签内
1.properties:读取外部资源,即用来存放数据的源信息
<properties resource="db.properties">
<property name="passwd" value="root"/>
</properties>
其中有两个属性,resource和name,resource为类路径下的的资源,url为网络路径或者磁盘路径下的资源,类似于数据库的url,数据库的用户名密码等等都是可变的,这里的db,properties是在resources包下的这个文件,里面按行写上:
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/test"
jdbc.username = root
jdbc.passwd = 123456 都直接写就行,不用以字符串的形式
但是原本的这些选项就不能再固定写死了,以${ }里面写参数的形式给出
<!--数据源配置-->
<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.usename}"/>
<property name="password" value="${jdbc.passwd}"/>
</dataSource>
</environment>
</environments>
在执行函数中这样写也可以读取到配置信息:
如果属性不至一个地方进行配置,mybatis将按照以下的顺序来加载:
• 首先读取在properties元素中指定的属性
• 然后根据properties元素中的resource/url属性指定的文件内容,并覆盖之前读取的同名的属性
• 最后读取作为方法参数传递的属性,并覆盖之前读取的同名属性
通过方法参数传递的属性具有最高优先级,resource或URL加载的属性次之,最低级的是properties元素体内的属性
2.setting:全局的参数配置
用的比较多的三个,还有很多,可以在官方文档上查看:
cacheEnable是二级缓存开关
LazeLoadingEnable和aggressiveLazyLoading配置懒加载的开关配置(延时加载)
<!--全局参数配置-->
<settings>
<!--开启二级缓存的开关-->
<setting name="cacheEnable" value="true"/>
<setting name="lazyLoadingEnable" value="true"/>
</settings>
3.typeAliases:类型别名:其实就是取别名,主要是针对xml配置文件的
<!--类型别名-->
<typeAliases>
<!--单个别名定义 type:pojo类的路径(全限定名) alias:别名的名称-->
<typeAlias type="com.tulun.MybatisDemo.Student" alias="student"/>
<!--批量的别名定义 name:指定的包名,将包下边的所有pojo类取别名,别名为类名(首字母大小写都行)-->
<package name="com.tulun.pojo"/>
</typeAliases>
即类似于select标签中的resultType就可以去替换而不用去引很长的路径
在mapper.xml 文件中,定义了很多的Statement,Statement需要parameterType指定输入参数类型,需要resultType指定输出参数类型,如果指定类型为全路径,开发不方便,可以针对parameterType和resultType指定的类型取别名,别名在配置文件(mybatis-config.xml)中配置typeAliases没在mapper.xml文件中使用
4.typeHandlers:类型处理器
数据库中的字符为varchar,Java代码中的字符为String,当然也有可能数据库中有int对应Java代码中的int,但当涉及到类型需要转换时,必须重写类型处理器
5.plugins:插件
可以对某一节点进行拦截调用,Spring AOC中会用到,再探讨底层原理
6.environments:环境配置
(因为当跟Spring整合后,环境配置可能最终是放在Spring中的,所以Mybatis大部分情况不需要去配置环境)
代码需要在不同的环境上跑,比如开发的时候在某台机子上跑,测试的时候又在其他机子上跑进行测试,线上又是其他环境,这些都需要不同的配置,你可以自己配置多个环境(不同的环境id,url,用户名密码都不同),SQLSessionFactory实例会去选取其中一种环境去运行
<!--数据源配置-->
<environments default="test">
<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/test"/>
<property name="username" value="${username}"/>
<property name="password" value="${passwd}"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="${username}"/>
<property name="password" value="${passwd}"/>
</dataSource>
</environment>
<environment id="online">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="${username}"/>
<property name="password" value="${passwd}"/>
</dataSource>
</environment>
</environments>
默认使用的环境 ID(比如:default=“development”)。
每个 environment 元素定义的环境 ID(比如:id=“development”)。
事务管理器的配置(比如:type=“JDBC”)。
数据源的配置(比如:type=“POOLED”)。
7.Mappers:映射器
定义的Sql都在XML文件中,此标签可以告诉Mybatis要去哪里寻找Sql语句,一共又三种映射方式
<!--配置映射 三种映射方式-->
<mappers>
<!--resource方式:单个mapper映射,xml和接口可以不再一个目录下
在StudentMapper.xml中定义namespace为mapper接口的地址,映射文件通过
namespace来找到mapper接口文件-->
<mapper resource="mapper/StudentMapper.xml"/>
<mapper resource="mapper/UsertMapper.xml"/>
<!--class方式:单个mapper映射,指定mapper接口的地址遵循规则
将mapper.xml和mapper.java放在同一个目录下,且文件名相同
-->
<mapper class="com.tulun.MybatisDemo.StudentMapper"/>
<mapper class="com.tulun.MybatisDemo.UserMapper"/>
<!--package方式:批量的mapper映射遵循的规则:将mapper.xml和mapper.java 放在
同一个目录下,且文件名相同-->
<package name="com.tulun.MybatisDemo"/>
</mappers>
五.Mapper XML 文件详解
即POJO实体类对应的Mapper.xml文件
首先先补充一下在XML文件中都是以标签的形式编码的,在最外层的标签一个代表开始,一个以斜杠结尾的表示结束,倘若你这个标签本身就很简单那你可以直接写成写成比如这种形式:
Mapper文件最外层的根标签为mapper,其中有一个属性为namespace,一般为其全限定名(即路径写法),因为resources包下对应的mapper包可能不止一个POJO实体对应的mapper配置文件,通过命名空间的全限定路径可以分别找到各自对应的接口,Mapper XML文件主要用的就是其增删改查标签:
1.select标签
查询数据
其中有两个必须具有的属性,一个是id,一个是resultType
id为当前命名空间下Statement的唯一标识,而Statement即JDBC中的执行SQL语句的对象//这里先放下等搞清楚各个类与XML文件的执行顺序后回来写清楚这里是怎么样对应的
resultType:将结果集映射为Java的对象,该属性值为映射对象的全限定名或者是别名(和resultMap二选一)
resultType和resultMap的区别:
这两个只能二选一使用,不能全部一起使用,当POJO实体类中声明的属性和对应数据库表中的属性字段不一致时,如果用resultType就会映射失败,就要用resultMap进行显性映射,感觉上会很麻烦
<resultMap id="studentMap" type=com.tulun.MybatisDemo.Student>
<!--
colum为数据库表的属性字段
property为POJO实体类对应的属性名
除了第一行写为id,其他都写为result
-->
<id column="SID" property="SID"/>
<result column="Sname" property="name"/>
<result column="Ssex" property="Ssex"/>
<result column="Sage" property="Sage"/>
</resultMap>
<!--查询标签:select-->
<select id="selectStudentByID" resultType="studentMap">
select * from Student where SID = #{sid}
</select>
2.insert 标签
添加数据
属性:
id属性(必须),唯一标识
parameterType(可以忽略)传入参数类型(入参还有parameterMap)
useGeneratedKeys(可以忽略)开启主键回写
<insert id="insertStudent" useGeneratedKeys="true" parameterType="com.tulun.Mubatis.Demostudent">
insert into Student(SID,Sname,Sage,Ssex) values(#{SID},#{Sname},#{Sage},#{Ssex})
</insert>
3.update 标签
修改数据
update的常用属性:
id属性(必须) 唯一标识
resultType和parameterType(可以忽略)
4.delete标签
删除数据
常用属性:
id属性(必须) 唯一标识
resultType和parameterType(可以忽略)
六.Jnuit测试介绍(为XML配置做铺垫)
Junit是用于编写和运行可重复的自动化测试的开源框架
Junit的依赖:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
1.生成测试类
在Idea下,在需要测试类的当前的窗口,直接快捷点:ctrl+shfit+t ,选择create New Test
2.选择要测试的类
3.生成测试类
private SqlSessionFactory sqlSessionFactory;
@Before
public void before() {
//mybatis配置文件
String resource = "mybatis-config.xml";
//通过mybatis提供的Resources类来得到配置文件流
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
//创建会话工厂,传输mybatis配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void selectStudentByID() {
//通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过反射机制来获取对应mapper实例
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//调用mapper实例下方法
Student student = mapper.selectStudentByID(1);
System.out.println(student);
sqlSession.close();
}
@Test
public void insertStudent() {
//通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过反射机制来获取对应mapper实例
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//插入数据
Student student1 = new Student();
student1.setSID(10);
student1.setname("tulun1");
student1.setSage(11);
student1.setSsex("nan");
mapper.insertStudent(student1);
//事务提交
sqlSession.commit();
//关闭资源
sqlSession.close();
}
4.常用的注解
@Before
当在测试方法之前需要执行一些操作可以放在@Before注解中
读取配置信息
@Test
@Test注解的会被当做测试用例,Junit每一次会创建一个新的测试实例,调用@Test注解方法
@After
After 注解是在Test注解调用之后才会进行执行,一般是进行资源的回收
虽说是注解但用法跟重写方法是一样的,只是最后先执行Before方法,其次Test方法,最后After方法
说到底,Junit还是用来测试我们所写的Sql语句的,我们不必运行整个程序,让所有对象都生成,只需要提取出来单个模块放到Test中去测试
main包中放我们自己的代码,所有的测试代码放到test中
Mybatis的使用方法
mybatis主要有两种使用方式,一种XML配置的形式,就是上面之前的笔记。另外一种是注解的形式,注解的形式使用起来会更简单,但不便于理解其底层原理。
以具体的业务需求场景为例:通过学号查询学生信息
首先我们需要在pojo下做好实体类,也就是与数据库表对应的实体,里面有set和get方法,在dao下做好该实体类的接口,里面声明好我们的业务方法
public interface StudentMapper1 {
/**
* 通过SID查询用户信息
* @param sid
* @return
*/
public Student getStudentByID(int sid);
}
接下来把我们的业务sql: select * from Student where SID = ? 封装到XML文件中
创建mapper.xml文件(在resources包下的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="com.tulun.dao.StudentMapper1">
<!--select * from Student where SID = ?-->
<!--
select查询操作标签
id属性:对应接口中的方法名,必填项,且在同一个namespace下,id不能重复
#{XXX}:占位符,里面添加的是方法中的参数名
parameterType属性:指定入参类型
resultType:执行返回参数类型,指定全路径名
resultMap属性:指定返回参数类型
-->
<select id="getStudentByID" parameterType="java.lang.Integer" resultType="com.tulun.pojo.Student">
select * from Student where SID = #{sid}
</select>
</mapper
XML文件外层要有约束,内层要有命名空间,把sql放入select标签中,id即对应的业务方法名,paramterType对应参数类型,不过这里要以路径形式给出包装类型,resultType即返回类型Student同样以路径形式给出。
之后在全局配置文件中给出此配置文件的路径(即最下面的以config结尾的那个XML文件)
<mappers>
<mapper resource="mapper/StudentMapper1.xml"/>
</mappers>
用Junit测试我们的业务接口,直接在Test包下的dao包下面创建Test测试类,将会话工厂之类的放在Before标签下,
public class StudentMapper1Test {
private SqlSessionFactory sqlSessionFactory;
@Before
public void before() {
//mybatis配置文件
String resource = "mybatis-config.xml";
//通过mybatis提供的Resources类来得到配置文件流
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
//创建会话工厂,传输mybatis配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void getStudentByID() {
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过接口产生代理类
StudentMapper1 mapper = sqlSession.getMapper(StudentMapper1.class);
Student student = mapper.getStudentByID(2);
System.out.println(student);
}
}
mapper.XML文件属性详解:
比如我们再需要去插入一个学生信息:
首先一样在之前的接口中声明好业务方法,再把业务sql insert into Student(SID,Sname,Ssex,Sage ) values(?,?,?,?); 封装到刚才的XML文件中
/**
* 插入单个学生信息
* @param student
* @return
*/
public int insertStudent(Student student);
直接写在刚才select标签下面
<!--插入单个学生信息-->
<!--
insert标签:插入操作
id属性:在当前的namespace中唯一标识
parameterType:传入参数的类型,是参数类型的全限定名,可选操作
flushCache属性:和一级二级缓存有关,true和false值,默认值true:在调用该语句是,会清空缓存
timeout:等待数据返回的超时时间
useGeneratedKeys属性:使用数据内部产生的主键 默认为false
keyColumn:指定数据库中的生成键
-->
<insert id="insertStudent" parameterType="com.tulun.pojo.Student" >
insert into Student(SID,Sname,Sage, Ssex) values (#{SID},#{name},#{Sage},#{Ssex})
</insert>
在编写Mapper的文件是需要遵循的开发规范,mybatis才能自动的生成接口的代理对象
开发规范
在编写Mapper的文件是需要遵循的开发规范,mybatis才能自动的生成接口的代理对象:
1、在mapper.xml文件中namespace和Mapper的接口文件的接口名保持一致
2、Mapper.java接口中的方法名和Mapper.xml中的Statement的ID保持一致
3、Mapper.java接口中方法的输入参数和mapper.xml文件中Statement的parameterType指定的类型一致
4、mapper.java接口中方法的返回值类型和mapper.xml文件中Statement的resultType指定的类型一致
注解形式的用法
注解的形式SQL语句直接写在接口上
优点:比较简单
缺点:当SQL发生改变,需要重新编译代码
select
public interface StudentMapper2 {
/**
* 通过SID查询学生信息
*/
@Select("select * from Student where SID=#{sid}")
public Student getStudentBySID(int sid);
}
只需再在全局配置文件中配置一条扫描包路径(给出该接口的包目录即可)的标签代码即可:
<package name="com.tulun.dao"/>
如果数据库字段和Java类属性不一致,使用@Results
其实跟resultMap标签是一样的:
再例如插入学生信息,直接写接口:
/**
* 插入学生信息
*/
@Insert("insert into Student(SID,Sname,Sage,Ssex) values(#{SID},#{name},#{Sage},#{Ssex})")
public int insertStudent(Student student);
使用mybatis自增主键
其实和XML还是一样的
强调:
Java进行Mybatis调用时:
sqlSessionFactorybuilder:mybbatis提供的创建sqlSessionFactory实例的类,通过读取配置文件来创建sqlSessionFactory
sqlSessionFactory:会话工厂,一般是用单例模式创建,用来创建sqlSession会话的
sqlSession:会话,是操作数据库的CRUD等,sqlSession不安全的,一般进行一次操作就使用一个新的会话
多个参数的传递
当传递多个参数时,需要注意的问题:
例如通过学生年龄和性别来查询学生信息
select * from Student where Sage=? and Ssex=?
mybattis配置如下:
执行会抛出异常:
XML可用的参数只有0,1,param1和Param2,Mybatis根据位置自定义的名字,可以将#{sex}改为#{0}或者#{param1},但这样是没有意义的
多参数传递是给参数配置@Param注解
@Select("select * from Student where Ssex=#{sex} and Sage = #{age}")
public Student getStudentByAgeAndSex(@Param("sex") String sex,@Param("age") int age);
配置注解后,mybatis自动的将参数封装成Map类型,@Param注解值作为Map中的key,参数值作为Map中的value,通过这种形式可以识别多参数的对应关系
{}和${}区别:
#{}占位符在执行过程中将#{}替换重"?"占位符,将参数值和SQL分开传递到服务器
#{}使用类似于JDBC编程中prepareStatment
SQL注入问题:
#{}不存在SQL注入问题,采用预编译机制,将SQL和参数分别传递给SQL服务器
${}存在SQL注入问题
动态SQL
Mybatis强大特征之一自安于他的动态SQL,采用是OGNL表达式来处理SQL,根据表达式的不同能够将SQL进行拼接和组装
主要动态SQL的标签if标签,where标签,trim(where,set)标签,foreach标签
以场景为例:
场景1:根据SID查询学生
场景2:根据年龄查询学生
场景3:根据性别查询学生
场景4:更加年龄和性别查询学生
四个场景对应方法,对应四个XML文件里的配置,是否可以根据传入参数的不同可以动态的处理Sql
if标签
<select id="getStudentBySexAndAge" resultType="com.tulun.pojo.Student">
select * from Student where 1=1
<if test="Sage != 0">
and Sage = #{Sage}
</if>
<if test="Ssex != null">
and Ssex = #{Ssex}
</if>
</select>
if表达式
一般使用是放在where条件后面
判断参数是否传递使用if test属性(必填)为true或者false
test使用OGNL表达式处理,返回true则进入到if标签的SQL,返回为false则不会进入if标签
参数处理:
假如不存Sage,Ssex: select * from Student where 1=1
假如传Sage,Ssex :select * from Student where 1=1 and Sage = #{Sage} and Ssex = #{Ssex}
假如传Sage:select * from Student where 1=1 and Sage = #{Sage}
假如传Ssex:select * from Student where 1=1 and Ssex = #{Ssex}
其实if标签里的语句相当于原本select语句后面差的部分,只是这时根据参数给的不一样哪个标签为true拼接哪个,假如我们给的是根据性别查,那Sage !=0 返回的肯定是true,Ssex返回的是false肯定就会把Sage那个if标签的语句拼接到原本select语句的后面
测试:
两个参数都传:
传递一个参数Ssex:
传递一个参数Sage:
不传参数:
where标签
一般和if标签一块使用,如果标签包含的元素有返回值就插入where,将紧随where后面的And或OR开头的,将他们剔除
<select id="getStudentBySexAndAge" resultType="com.tulun.pojo.Student">
select * from Student
<where>
<if test="Sage != null">
and Sage = #{Sage}
</if>
<if test="Ssex != null">
and Ssex = #{Ssex}
</if>
</where>
</select>
值传递Sage:select * from Student where Sage = #{Sage};
不传递:select * from Student
两个都传递:select * from Student where Sage = #{Sage} and Ssex = #{Ssex}
跟if类似,直接在sql语句后面拼接where关键字和if标签成立的语句
测试:
无参:
传递一个参数Sage:
传递多个参数:
trim标签用于取出SQL中多余And关键字,逗号,使用在where或者set中
属性 | 描述 |
---|---|
prefix | 给sql拼接的前缀 |
suffix | 给sql拼接的后缀 |
prefixOverrides | 提出sql前面的关键字或者字符 |
suffixOverrides | 去除sql后面的关键字或者字符 |
<!--trim标签(where)-->
<select id="getStudentBySexAndAge" resultType="com.tulun.pojo.Student">
select * from Student
<trim prefix="where" prefixOverrides="and">
<if test="Sage != null">
and Sage = #{Sage}
</if>
<if test="Ssex != null">
and Ssex = #{Ssex}
</if>
</trim>
</select>
这个测试样例prefix=“where” prefixOverrides=“and” 相当于在sql后面拼接一个where关键字并且剔除and关键字即小面if标签中前面的and会被删掉
测试:
两个参数都传:
类似于更新标签可以这样写:
并且可以用trim去掉后面的逗号
foreach标签
批量处理
场景:通过一批SID查询用户信息
select * from Student where SID in(1,2,3);
insert into Student (SID,Sname) values (1,“zhansan”), (2,“zhansan”), (2,“zhansan”);
接口文件中的方法:
/**
* 批量查询
*/
public List<Student> batchSelectStudentByIds(List<Integer> ids);
Mapper.XML文件:
<!--批量查询SQL-->
<!--
foreach表达式
collection属性(必填)指定输入参数类型
list:列表
array:数组
map:map集合
item属性:取名称,给集合中单个元素的名称
open属性:开始的字符串
close属性:结束的字符串
separator属性:数据之间的分割符
-->
<select id="batchSelectStudentByIds" resultType="com.tulun.pojo.Student">
-- select * from Student where SID in(1,2,3);
select * from Student where SID in
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
测试:
模糊匹配(其实就是sql中的通配符)
需求:查询Student表,表中含有"L”的所有用户
SQL:select * from Student where Sname like “%L%”;
方式1:直接在参数上拼接通配符
mapper.getStudentsByName("%L%");
mapper.xml文件
测试用例:
方法2:Mysql中的concat(,)
concat(par1,par2) :进行字符串拼接
Mapper.xml配置
测试用例:
方法3:bind表达式处理
Mybatis提供的bind表达式
mapper.xml文件配置
接口方法: