在工作中发现对MyBatis还是有了解不到位的中央,所以就打算重新学习一下MyBatis。
简介
MyBatis 是一款优良的长久层框架,它反对自定义 SQL、存储过程以及高级映射。MyBatis 罢黜了简直所有的 JDBC 代码以及设置参数和获取后果集的工作。MyBatis 能够通过简略的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,一般老式 Java 对象)为数据库中的记录。
首先是MyBatis给本人的定位是长久层框架,那什么是长久层,简略的说就是和数据库沟通的那一层,也就是MVC模式下的dao(Data Access Object)层,dao层的代码负责将业务代码变成对数据库表的操作,至于为什么叫长久层,我感觉是跟数据库的持久性特点有关系呢!
在dao层没有任何框架之前,咱们是间接应用原生的jdbc来操纵数据库的数据,拼接SQL,设置参数,获取后果集重复性的工作经常让人非常腻烦,然而JDBC从设计思路上讲也足够优良了,做到了跨数据库,让使用者不用关怀是哪个数据库,而采取不同的操作,JDBC就是一组接口,由各大数据库厂商提供对应的实现类,所以也不大可能做齐全的定制的化操作,所以JDBC的设计思维就是宽泛一点。
然而咱们心愿简略点,所以如果你看视频去学习的话,基本上学完JDBC,就会讲如何封装一个工具类JdbcUtils,来防止反复代码的编写,但这并不是一个Java程序员的痛点,对吗?Java社区也关注到了这个问题,开始着手对JDBC进行扩大,进行降级。这也就是MyBatis、Hibernate、Spring Data JPA等ORM框架。
等等你方才又提到了一个名词,ORM框架,那什么是ORM框架? ORM Object Relational Mapping 即对象关系映射,听起来好形象啊! 不要焦急,听我细细道来,Java是一门面向对象的语言,咱们当初广泛应用的数据库是关系型数据库(表为次要模式),ORM的思维就是是否将表映射为对象呢? 一条数据记录就是一个对象。
所以MyBatis是一款优良的长久层、ORM框架,在JDBC的根底上进行扩大、封装,罢黜了简直所有JDBC代码以及设置参数和获取后果集的工作,大大简化了长久层代码开发。
对简化了长久层代码的开发,简略点,简略点,咱们都喜爱简略的货色。
如何学习一门技术?
个别状况,学一门框架,最好还是去官网去学,以前我是图速度快,去B站找的视频。当初发现MyBatis官网写的教程挺不错的,更让我喜爱的是有中文版本:
好到我让我感觉我这篇博客,是不是还是有必要写。然而思虑再三,还是打算写,官网文档配合本人的了解,让本人的常识更成零碎。
筹备工作
要用MyBatis,咱们首先要引入MyBatis,MyBatis是在原生JDBC的根底上做扩大,所以咱们要引入对应的数据库驱动(数据库驱动就是数据库厂商实现的JDBC),本篇咱们应用的是MySQL,Druid来治理数据库连贯。 本篇咱们仍然应用Maven来搭建我的项目:
对应的依赖如下:
<dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.30</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.30</version> <scope>test</scope> </dependency>
slf4j是日志框架,输入的信息会更粗疏,倡议引入。
如果你不会用maven
倡议你去学maven,参看我这篇博客: Maven学习笔记,十分通俗易懂的入门。
如果你不想学Maven,想用jar包模式,也行,我的博客就是这么贴心,哈哈哈哈。
- 首先进入MyBatis官网。
3.
第一个MyBatis 程序
首先咱们要建一个配置文件
对了还要建一个表,如果你不懂的建表,本篇文章可能就不适宜你,我建的表叫Blog。
表语句我就不放了,最近重学SSM,写了一些例子,都放在GitHub上了,上面是链接:
- https://github.com/CXK6013/SSM
大略解释一下配置文件
<?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> <!--加载配置文件--> <properties resource="jdbc.properties"/> <!--指定默认环境, 个别状况下,咱们有三套环境,dev 开发 ,uat 测试 ,prod 生产 --> <environments default="development"> <environment id="development"> <!-- 设置事务管理器的治理形式 --> <transactionManager type="JDBC"/> <!-- 设置数据源连贯的关联形式为数据池 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.dev.driver}"/> <property name="url" value="${jdbc.dev.url}"/> <property name="username" value="${jdbc.dev.username}"/> <property name="password" value="${jdbc.dev.password}"/> </dataSource> </environment> </environments> <mappers> <!--设置扫描的xml,org/example/mybatis是包的全类名,这个BlogMapper.xml会讲--> <mapper resource="org/example/mybatis/BlogMapper.xml"/> </mappers></configuration>
Hello World
新建一个接口
public interface BlogMapper { Blog selectBlog(Long id);}
新建一个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"><!-- 这里的namespace必须是BlogMapper的全类名 --><mapper namespace = "org.example.mybatis.BlogMapper"> <!-- MyBatis 会主动将查问进去的记录封装为resultType设定类型的对象,这里领会一下ORM的思维--> <select id = "selectBlog" resultType = "org.example.mvc.entity.Blog"> select * from Blog where id = #{id} </select></mapper>
测试代码
public static void main(String[] args) throws IOException { String resource = "mybatis-config.xml"; // 读取配置文件 InputStream inputStream = Resources.getResourceAsStream(resource); // 构建一个SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 开启一个会话 SqlSession sqlSession = sqlSessionFactory.openSession(); // 加载指定的接口 BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class); // 调用接口中的办法,相当于执行对应mapper中的查问语句 Blog blog = blogMapper.selectBlog(1L); // 打印查问语句 System.out.println(blog); }
执行后果:
总结一下
第一个程序可能还比拟晕哈,先跟着做,而后咱们来解释一下MyBatis做了什么:
那BlogMaper.java到底是怎么和BlogMapper.xml关联起来的呢? 还记得下面的配置吗?
实质上还是动静代理,运行时创立接口的实现类,如果你不懂什么是动静代理,请参看:
- 代理模式-AOP绪论
用MyBatis操纵数据库的根本流程:
- 新建接口
- 建xml,这里要留神一下,XML也不能瞎建,下面的束缚还是要留神一下:
不必记也没关系,能够在MyBatis官网拷贝一下:
- 在配置文件的mapper标签,开启扫描标签,关联接口和xml文件(能够批量设定的,前面会讲)
- 而后SqlSession对象的获取指定接口的办法,即可调用对应的SQL语句。
认真领会下,这样绝对于原生的JDBC是不是更加清晰了呢。
传递参数
下面咱们在调用BlogMapper中的selectBlog仅仅只是在接口中写了参数,MYBatis就能主动的将#{id}替换为咱们传递的参数,是不是很弱小呢! 这种形式也反对多个参数,然而该SQL须要的参数有七八个怎么办?接口办法上写七八个参数? 其实也行,那传的是一个数组或者List呢? MyBatis能遍历一下吗? MyBatis: 当然反对。
对于数据库来说,查总是最让咱们关怀的,select标签的属性也是最多的,如上面代码所示:
<select id="selectPerson" parameterType="int" parameterMap="deprecated" resultType="hashmap" resultMap="personResultMap" flushCache="false" useCache="true" timeout="10" fetchSize="256" statementType="PREPARED" resultSetType="FORWARD_ONLY"></select>
这些属性在MyBatis官网有具体的介绍:
咱们这里只拎进去罕用的来介绍,在传递参数这里,咱们介绍的就是parameterType(参数类型)属性,这个属性是可选的,MyBatis能够通过Typehandler来推断进去传递的参数,来将咱们SQL语句中的#{id}(咱们下文会对立称之为占位符)替换掉。
留神单个参数,占位符中参数名和办法中的参数名无需保持一致。多个参数时,就须要启用@Param
注解了。@Param中的属性值要和占位符中的参数名保持一致,不然MyBatis拿到两个参数值,无奈推断出应该用哪个值替换占位符。
如果你想要用对象
间接传对象(Map也是一样), 而后在占位符中写对应的属性名(Map的时候是key)即可:
<!-- 留神这个时候写在占位符中的属性名要有get办法,否则调用会失败--> <select id="selectBlogByObj" resultType="org.example.mvc.entity.Blog" > select * from Blog where id = #{id} </select>
测试代码:
public static void main(String[] args) throws IOException { selectByObj(); } private static void selectByObj() throws IOException { BlogMapper blogMapper = getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setId(1L); blog.setName("aa"); blog = blogMapper.selectBlogByObj(blog); System.out.println(blog); } public static <T> T getMapper(Class<T> t) throws IOException { String resource = "mybatis-config.xml"; // 读取配置文件 InputStream inputStream = Resources.getResourceAsStream(resource); // 构建一个SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 开启一个会话 SqlSession sqlSession = sqlSessionFactory.openSession(); return (T) sqlSession.getMapper(t); }
运行后果:
上面再介绍应用的时候,不会再贴getMapper和main办法,只写对应的办法。
汇合
遍历List 、数组 、Map
汇合经常被用来构建in语句,那么在xml中怎么遍历呢? 通过foreach标签来遍历,像上面这样:
<select id = "selectBlogByList" resultType="org.example.mvc.entity.Blog"> select * from Blog where id in <foreach collection="list" item="item" open="(" separator="," close=")"> #{item} </foreach> </select>
这个foreach标签就是把java中foreach映射进到xml了而已。item是迭代元素 , list是迭代的汇合。open、close用于指定拼接造成的字符串,以及汇合项迭代的分隔符。也就是说假如我传入的List有1,2这两个元素,最终造成的sql语句就会是上面这样:
select * from Blog where id in (1,2)
看MyBatis 如许的智能。如果汇合类型是Map的时候,index 是键,item 是值。
下面我查到的可能是多个对象,那在MyBatis中应该怎么接管呢?只用将该标签id对应的办法改为List<Blog>
就行。
List<Blog> selectBlogByArray(Long[] idLongArray);
默认状况下,collection即为汇合名的纯小写,比方传入的是List类型,那么Collection中就应该写list。如果是数组就应该写Array。如果用@Param指定了参数名,那么就写@Param中指定的参数名。
返回类型
Map
下面咱们曾经讲了返回一条数据和返回多条数据,这个用Map接管返回类型,看上去有点违反直觉,事实上他也是完全符合直觉的。咱们用Map接管一下试试看:
<select id = "selectAllReturnMap" resultType="map"> select * from Blog</select>
接口中申明的办法:
Map<String,Object> selectAllReturnMap();
private static void selectAllReturnMap() throws IOException { BlogMapper blogMapper = getMapper(BlogMapper.class); System.out.println(blogMapper.selectAllReturnMap()); }
测试后果如下:
粗心就是返回了三个,你用一个接管,接管不了。
可能这个时候又同学就会问了,Map不是能装多组值吗? 为啥收不了三条记录,那咱们想一下Map的key是不是不能反复,三条记录的key都是属性名,某种意义上一个Map就是一个对象,key就是属性名,value就是属性值。所以咱们应该这么收:
List<Map<String,Object>> selectAllReturnMap();
测试后果:
{占位符} VS ${占位符}
下面咱们用的替换参数的占位符,都是#号结尾的,MyBatis会把#{参数名}替换为咱们调用接口对应办法时传递的参数值,个别咱们称之为#号占位符,其实还有一种是以$结尾的。咱们称之为dollar(刀乐)占位符。默认状况下,应用 #{} 参数语法时,MyBatis 会创立 PreparedStatement 参数占位符,并通过占位符平安地设置参数(就像应用 ? 一样)。
上面咱们用一个例子来感受一下两者的不一样,咱们先配下日志,日志输入真正执行的SQL,不便咱们剖析问题
咱们依照要求引入对应的依赖:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.12.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j</artifactId> <version>2.14.0</version> <type>pom</type> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
而后在resources建一个文件log4j.properties,文件内容如下:
# 全局日志配置log4j.rootLogger=DEBUG,ERROR, stdout# MyBatis 日志配置 会输入执行包下的详细信息log4j.logger.org.mybatis.example=DEBUG # 控制台输入log4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
这个照着贴就行,介绍日志并不是本篇的内容,咱们是借助日志来钻研井号占位符和美元占位符的不同之处。
而后在配置文件中开启日志:
<settings> <setting name="logImpl" value="LOG4J"/> </settings>
号占位符
xml中的代码:
<select id="selectByMark" resultType = "org.example.mvc.entity.Blog"> select * from Blog where id = #{id} and name = #{name} </select>
BlogMapper.中的代码:
List<Blog> selectByMark(@Param("id") String id,@Param("name") String name);
测试代码:
private static void markVsDollar() throws IOException { BlogMapper blogMapper = getMapper(BlogMapper.class); blogMapper.selectByMark("1","aa; delete Blog;"); // blogMapper.selectByDollar("1","aa; delete Blog"); }
执行后果:
DEBUG [main] - Created connection 551479935.DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@20deea7f]DEBUG [main] - ==> Preparing: select * from Blog where id = ? and name = ?DEBUG [main] - ==> Parameters: 1(String), aa or 1 = 1(String)DEBUG [main] - <== Total: 0
所以最终的SQL语句就是: select * from Blog where id = '1' and name = 'aa or 1 = 1'
咱们的数据库并没有这样的数据,所以一条这样的数据都没查出来。
$号占位符
xml中的代码:
<select id="selectByDollar" resultType = "org.example.mvc.entity.Blog"> select * from Blog where id = ${id} and name = ${name} </select>
List<Blog> selectByDollar(@Param("id") String id, @Param("name") String name);
测试代码:
private static void markVsDollar() throws IOException { BlogMapper blogMapper = getMapper(BlogMapper.class); blogMapper.selectByDollar("1","1 or 1 = 1;"); }
执行后果:
DEBUG [main] - Created connection 1327006586.DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@4f18837a]DEBUG [main] - ==> Preparing: select * from Blog where id = 1 and name = 1 or 1 = 1;DEBUG [main] - ==> Parameters: DEBUG [main] - <== Total: 2
各位认真的比照一下两个理论执行的SQL语句,一个Parameters有值,有参数类型,一个没有,间接是原样替换。
第二种事实上被称之为SQL注入,查到了不应该查到的记录。然而$号占位符也不是一无是处,比方在排序的时候,依据前端传递的字段来进行排序:
ORDER BY ${columnName}
可能有同学会说,这样是不是仿佛也有注入危险,不按约定的字段,轻易穿了一个过去,而后不就报错了,防止这个问题能够在Java中做判断,只有是约定的字段才会传给真正执行的SQL。
总结一下
井号占位符会主动给咱们本义,依据类型来判断转不本义,如果是字符串类型,MyBatis会主动为咱们将参数上加上引号。如果是数字类型,就不会加上。
美元占位符是原样替换,有SQL注入的危险,但有的时候在咱们并不想MyBatis为咱们拼上引号的时候,比如说依据前端传递的字段来进行排序,所以$占位符要慎用。
update、delete、insert、调用存储过程
数据变更语句 insert,update 和 delete 的实现十分靠近:
<insert id="insertAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" keyProperty="" keyColumn="" useGeneratedKeys="" timeout="20"><update id="updateAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20"><delete id="deleteAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20">
parameterType类型和select标签的parameterType应用形式一样,咱们次要讲statementType、useGeneratedKeys。
statementType: 可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 别离应用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
JDBC根底不扎实的同学,可能会问Statement、PreparedStatement 、CallableStatement是啥?
简略的说,Statement接口提供了执行语句和获取后果的根本办法;PreparedStatement接口增加了解决输出参数的办法;
CallableStatement接口增加了调用存储过程核函数以及解决输入参数的办法。
useGeneratedKeys 应用示例
<!-- useGeneratedKeys 开启接管主键 keyProperty 将返回的主键放在对象的哪个属性上 --><insert id="insertEntity" useGeneratedKeys="true" keyProperty="id" > insert into Blog (name) values (#{name})</insert>
java代码:
private static void insertEntity() throws IOException { String resource = "mybatis-config.xml"; // 读取配置文件 InputStream inputStream = Resources.getResourceAsStream(resource); // 构建一个SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 开启一个会话 SqlSession sqlSession = sqlSessionFactory.openSession(); BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class); Blog blog = new Blog(); blog.setName("aaa"); blogMapper.insertEntity(blog); // 记得提交 sqlSession.commit(); // 敞开会话,不然新增不会胜利 sqlSession.close(); System.out.println(blog); }
所以下面的getMapper办法,咱们还要再革新一下,理论应用中也就是SSM(Spring Spring MVC MyBatis)整合之后,引入数据库连接池之后,连贯应用结束之后会还给连接池,这里咱们就不革新了。
测试后果:
数据库后果:
数据库反对自增主键能够这么搞,不反对的就不能够这么搞了。
罕用标签
下面咱们在介绍参数类型是汇合时,曾经介绍了遍历标签,<foreach>
, 然而有循环,怎么能够没有判断,switch呢。那怎么把逻辑判断移入xml中呢? 将判断变成一个一个标签吗? 那得记住多少标签啊? MyBatis的前身iBatis就这么做的,MyBatis做出的扭转就是通过OGNL表达式配合if标签来实现逻辑判断。
OGNL表达式简介
OGNL(Object-Graph Navigation Language)是一种表达式语言(EL),简略来说就是一种简化了的Java属性的取值语言,在传统的Struts框架,以及MyBatis中都有大量应用,开源Java诊断利器Arthas也应用它做表达式过滤,简略但不失灵便的设计衍生进去了好多高阶玩法。
咱们这里简略的介绍一下罕用的,详情能够参看OGNL官网文档: http://commons.apache.org/pro...
OGNL生来就是为了简化Java属性的取值,比方想依据名称name援用以后上下文环境中的对象,则间接键入即可,如果想要援用以后上下文环境中对象text的属性title,则键入text.title即可。如果调用对象的办法,间接通过对象.办法名()即可。
拜访数组,间接通过数组名[索引]拜访即可。
判断参数不为null 和 汇合size大于0
<select id="selectBlogByList" resultType="org.example.mvc.entity.Blog"> select * from Blog where id in <if test = "list != null and list.size() > 0"> <foreach collection="list" item="item" open="(" separator="," close=")"> #{item} </foreach> </if> </select>
参数值等于某个字符串
<select id="selectByMark" resultType="org.example.mvc.entity.Blog"> select * from Blog where id = #{id} <if test = ' "张三".equals(name) '> and name = #{name} </if> </select>
choose、when、otherwise
有时候,咱们不想应用所有的条件,而只是想从多个条件中抉择一个应用。针对这种状况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。为了丰盛咱们的实用场景,咱们又向Blog表里加了两个字段:title和status,以前只有id,name。
示例:
<select id="testChoose" resultType="org.example.mvc.entity.Blog"> select * from Blog where status = 'active' <choose> <when test="title != null"> AND title like #{title} </when> <when test=" name != null "> AND name like #{name} </when> <otherwise> AND status != 'active' </otherwise> </choose> </select>
如果title不为空,就搜寻title,如果name不为空, 就含糊搜寻name。如果这两个都是空,就去搜寻status 不是active的。
where、trim、set
后面的示例咱们曾经解决了拼接SQL的问题,上面咱们来看上面一个SQL:
select * from Blog where id in <if test = "list != null and list.size() > 0"> <foreach collection="list" item="item" open="(" separator="," close=")"> #{item} </foreach> </if>
如果条件不成立,SQL就会变成这样:
select * from Blog where id in
很显著这会报错,那为了防止这种状况,咱们是不是要在where 前面拼接一个 1 = 1呢? 而后SQL就变成了上面这样:
select * from Blog where 1 = 1 <if test = "list != null and list.size() > 0"> id in <foreach collection="list" item="item" open="(" separator="," close=")"> #{item} </foreach> </if>
然而这相当不优雅,MyBatis提供了<where>
标签,where 元素只会在子元素返回任何内容的状况下才插入 “WHERE” 子句。而且,若子句的结尾为 “AND” 或 “OR”,where 元素也会将它们去除。所以咱们的SQL能够就变成了这样:
<select id="selectBlogByList" resultType="org.example.mvc.entity.Blog"> select * from Blog <where> <if test = "list != null and list.size() > 0"> id in <foreach collection="list" item="item" open="(" separator="," close=")"> #{item} </foreach> </if> </where> </select>
如果 where 元素与你冀望的不太一样,你也能够通过自定义 trim 元素来定制 where 元素的性能。比方,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ...</trim>
prefixOverrides 属性会疏忽通过管道符分隔的文本序列(留神此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
用于动静更新语句的相似解决方案叫做 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 元素等价的自定义 trim 元素吧:
<trim prefix="SET" suffixOverrides=","> ...</trim>
留神,咱们笼罩了后缀值设置,并且自定义了前缀值。
bind标签
bind 元素容许你在 OGNL 表达式以外创立一个变量,并将其绑定到以后的上下文:
<select id="selectByMark" resultType="org.example.mvc.entity.Blog"> select * from Blog where id = #{id} <if test = ' "张三".equals(name) '> <bind name="pattern" value="'%' + name + '%'" /> and name = #{pattern} </if></select>
别名
还记得咱们在配置文件中配置的mappers吗? 咱们其实也能够批量配置 ,批量关联:
<mappers> <!--批量关联--> <package name = "org.example.mybatis"/> </mappers>
咱们的resultType写的是全类名,那不能不写那么多呢? 能够,在配置文件中这样配置就能够了:
<typeAliases> <package name="org.example.mvc.entity"/> </typeAliases>
留神这个程序,只能按properties、settings、typeAliases这个程序来。
而后咱们写resultType中的值写类名就能够了。
类型转换器
当初咱们来关注一下,MyBatis实现ORM的一组外围类,类型转换器。咱们下面讲MyBatis将表的记录变成Java中的对象,那数据类型是怎么对的上的呢? 就是通过类型转换器:
能够重写已有的类型处理器或创立你本人的类型处理器来解决不反对的或非规范的类型, 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便当的类 org.apache.ibatis.type.BaseTypeHandler, 并且能够(可选地)将它映射到一个 JDBC 类型。
间接实现TypeHandler接口还是有点麻烦的,所以咱们这里介绍的是继承BaseTypeHandler来领会MyBatis中类型转换器的弱小性能。BaseTypeHandler概览:
转换器是双向的,所以就有从数据库到Java的,从Java到数据库的:
setNonNullParameter Java到数据库就是剩下的剩下的三个get办法,从名字上咱们就能够推断进去,是从数据库到Java的。
这次咱们定义的类型转换器就是将Java的Boolean转成数据库中的int类型。
public class MyTypeHandler extends BaseTypeHandler<Boolean> { // java-DB @Override public void setNonNullParameter(PreparedStatement ps, int i, Boolean parameter, JdbcType jdbcType) throws SQLException { if (parameter) { ps.setInt(i, 1); } else { ps.setInt(i, 0); } } // DB-java @Override public Boolean getNullableResult(ResultSet rs, String columnName) throws SQLException { return rs.getInt(columnName) == 1 ? true : false; } // DB-java @Override public Boolean getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return rs.getInt(columnIndex) == 1 ? true : false; } // java-Db @Override public Boolean getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return cs.getInt(columnIndex) == 1 ? true : false; }}
而后在Blog实体和表中退出对应的字段,Blog为Boolean,Blog表为int ,这里不再做展现了。
而后咱们在配置文件中注册应用这个类型转换器:
<typeHandlers> <package name="org.mybatis.example"/></typeHandlers>
测试代码:
private static void selectBlogByCollection() throws IOException { BlogMapper blogMapper = getMapper(BlogMapper.class); List<Long> idLongList = new ArrayList<>(); idLongList.add(1L); System.out.println(blogMapper.selectBlogByList(idLongList));}
数据库中的值:
测试后果:
转换胜利。
总结一下
本篇次要讲的是MyBatis的根本应用,如何配置、传参、返回类型、占位符、罕用标签、OGNL表达式。开篇讲的基本上都是应用频率很高的,这算是把MyBatis又重学了一遍,以前学MyBatis看视频,当初发现如果官网文档写的比拟丰盛的话,看官网文档是更好的抉择。心愿对会大家有所帮忙
参考资料
- MyBatis官网文档
- MyBatis视频教程
- OGNL语法标准