MyBatis学习笔记(参考官方文档 3.5.4版本)
安装使用
创建Maven工程
在pom.xml中引入Maven依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <dependencies > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.4</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.19</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.12</version > <scope > compile</scope > </dependency > </dependencies >
在resources目录下创建mybatis-config.xml全局配置文件(这里参考官方文档创建格式)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?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.cj.jdbc.Driver" /> <property name ="url" value ="这里配置数据库URL" /> <property name ="username" value ="你的数据库账号" /> <property name ="password" value ="你的数据库密码" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="mappers/BlogMapper.xml" /> </mappers > </configuration >
根据官方文档给出的信息在Java目录下创建实体类、映射接口和测试类
1 2 3 4 5 package entity;public class Blog { }
1 2 3 4 5 6 7 8 package mapper;import entity.Blog;public interface BlogMapper { Blog selectBlog (Long id) ; }
在resources下创建mappers文件夹用来放入mapper配置文件,创建BlogMapper接口类的映射文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?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.BlogMapper" > <select id ="selectBlog" resultType ="Blog" > select * from Blog where id = #{id} </select > </mapper >
对命名空间的一点补充
在之前版本的 MyBatis 中,命名空间(Namespaces) 的作用并不大,是可选的。 但现在,随着命名空间越发重要,你必须指定命名空间。
命名空间的作用有两个,一个是利用更长的全限定名来将不同的语句隔离开来,同时也实现了你上面见到的接口绑定。就算你觉得暂时用不到接口绑定,你也应该遵循这里的规定,以防哪天你改变了主意。 长远来看,只要将命名空间置于合适的 Java 包命名空间之中,你的代码会变得更加整洁,也有利于你更方便地使用 MyBatis。
对于映射类还有另一种注解 的配置方法,比如,上面的 XML 示例可以被替换成如下的配置:
1 2 3 4 public interface BlogMapper { @Select ("SELECT * FROM blog WHERE id = #{id}" ) Blog selectBlog (int id) ; }
优先使用XML配置文件的方式开发
创建完成后层级目录如下图:
XML 配置 配置文档的顶层结构如下:
属性(properties) 1 2 3 4 5 6 7 8 9 10 <properties resource ="org/mybatis/example/config.properties" > <property name ="username" value ="dev_user" /> <property name ="password" value ="F2Fa3!33TYyg" /> </properties >
设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值
1 2 3 4 5 6 7 8 9 <dataSource type ="POOLED" > <property name ="driver" value ="${driver}" /> <property name ="url" value ="${url}" /> <property name ="username" value ="${username}" /> <property name ="password" value ="${password}" /> </dataSource >
类型别名(typeAliases) 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
1 2 3 4 5 6 7 8 <typeAliases > <typeAlias alias ="Author" type ="domain.blog.Author" /> <typeAlias alias ="Blog" type ="domain.blog.Blog" /> <typeAlias alias ="Comment" type ="domain.blog.Comment" /> <typeAlias alias ="Post" type ="domain.blog.Post" /> <typeAlias alias ="Section" type ="domain.blog.Section" /> <typeAlias alias ="Tag" type ="domain.blog.Tag" /> </typeAliases >
映射器(mappers) 1 2 3 4 5 6 <mappers > <mapper resource ="org/mybatis/builder/AuthorMapper.xml" /> <mapper resource ="org/mybatis/builder/BlogMapper.xml" /> <mapper resource ="org/mybatis/builder/PostMapper.xml" /> </mappers >
1 2 3 4 5 6 <mappers > <mapper url ="file:///var/mappers/AuthorMapper.xml" /> <mapper url ="file:///var/mappers/BlogMapper.xml" /> <mapper url ="file:///var/mappers/PostMapper.xml" /> </mappers >
1 2 3 4 5 6 <mappers > <mapper class ="org.mybatis.builder.AuthorMapper" /> <mapper class ="org.mybatis.builder.BlogMapper" /> <mapper class ="org.mybatis.builder.PostMapper" /> </mappers >
1 2 3 4 <mappers > <package name ="org.mybatis.builder" /> </mappers >
XML映射器
1 2 3 4 <select id ="selectPerson" parameterType ="int" resultType ="HashMap" > SELECT * FROM PERSON WHERE ID = #{id} </select >
官方提供的select语句的标签属性:
1 2 3 4 5 6 7 8 9 10 11 12 <select id ="selectPerson" //命名空间中唯一标识符 parameterType ="int" //可选,传入参数的类全限定名或别名 parameterMap ="deprecated" //已废弃 resultType ="hashmap" //返回结果的类全限定名或别名 resultMap ="personResultMap" //对外部 resultMap 的命名引用,resultType 和 resultMap 之间只能同时使用一个 flushCache ="false" //是否清空本地缓存和二级缓存,默认为false useCache ="true" //是否启用二级缓存 timeout ="10" //在抛出异常之前,驱动程序等待数据库返回请求结果的秒数 fetchSize ="256" //让驱动程序每次批量返回的结果行数等于这个设置值 statementType ="PREPARED" //可选 STATEMENT ,PREPARED 或 CALLABLE resultSetType ="FORWARD_ONLY" //FORWARD_ONLY ,SCROLL_SENSITIVE , SCROLL_INSENSITIVE 或 DEFAULT (等价于 unset ) 中的一个>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <insert id ="insertAuthor" > insert into Author (id,username,password,email,bio) values (#{id},#{username},#{password},#{email},#{bio}) </insert > <update id ="updateAuthor" > update Author set username = #{username}, password = #{password}, email = #{email}, bio = #{bio} where id = #{id} </update > <delete id ="deleteAuthor" > delete from Author where id = #{id} </delete >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <insert id ="insertAuthor" parameterType ="domain.blog.Author" flushCache ="true" statementType ="PREPARED" keyProperty ="" //(仅适用于 insert 和 update )指定能够唯一识别对象的属性 keyColumn ="" //(仅适用于 insert 和 update )设置生成键值在表中的列名 useGeneratedKeys ="" //(仅适用于 insert 和 update )取出由数据库内部生成的主键 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" >
有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句,这时候你可以:
当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。举个例子,如果你想 select 一个表任意一列的数据时,不需要这样写:
1 2 3 4 5 6 7 8 @Select ("select * from user where id = #{id}" )User findById (@Param("id" ) long id) ;@Select ("select * from user where name = #{name}" )User findByName (@Param("name" ) String name) ;@Select ("select * from user where email = #{email}" )User findByEmail (@Param("email" ) String email) ;
而是可以只写这样一个方法:
1 2 @Select ("select * from user where ${column} = #{value}" )User findByColumn (@Param("column" ) String column, @Param ("value" ) String value) ;
其中 ${column} 会被直接替换,而 #{value} 会使用 ? 预处理。 这样,就能完成同样的任务:
1 2 3 User userOfId1 = userMapper.findByColumn("id" , 1L ); User userOfNameKid = userMapper.findByColumn("name" , "kid" ); User userOfEmail = userMapper.findByColumn("email" , "noone@nowhere.com" );