本文最后更新于:2022-10-09T20:28:36+08:00
快速开始
简介
MyBatis最初来源于Apache的开源项目iBatis,后续迁移到Google之后,更名为MyBatis,在后续的包名中,我们还可以看到iBatis的踪迹。
MyBatis是一个基于Java的持久层框架,它支持定制化SQL,存储过程以及高级映射。它避免了几乎所有的JDBC代码,手动拼接参数,结果集获取等操作,而是使用简单的XML或者注解来对应配置和映射,将接口与Java中的普通Java对象(Plain
Old Java Objects)映射成数据库中的记录。
MyBatis的下载地址在此:mybatis/mybatis-3: MyBatis
SQL mapper framework for Java (github.com)
持久层技术除了MyBatis还有很多,各个框架各有特点。
对于JDBC,SQL会夹杂在Java代码中,导致耦合度高,维护不方便,需要频繁修改源代码;并且代码冗长,开发效率低
对于Hibernate和JPA,它的操作简便,开发效率高,但是程序中无法直接使用复杂的SQL,并且内部自动产生的SQL不容易做特殊优化。这是一个基于全映射的全自动框架,如果一个实体类有大量字段,在进行映射的时候会比较困难,并且其中反射操作太多,会导致数据库性能下降
对于MyBatis,它是一个轻量级,性能出色的持久层框架,在其中SQL与Java代码分离,分工明确。Java代码专注业务,SQL语句专注数据逻辑。虽然开发效率稍低于Hibernate,但是在接受范围内
入门案例
下面我们通过一个入门案例来快速学习MyBatis的使用。其中部分配置文件的内容可以参考:入门_MyBatis中文网
首先我们准备相关的数据库测试环境。这里我们在本地的MySQL数据库中创建一个表格users,其中的字段分别有id
、username
、password
、age
、gender
、email
。
之后我们来添加相关依赖,除了MyBaits的依赖项,还包括其他一些相关的辅助依赖,需要注意的是这些依赖并不是MyBaits必须的,而是方便我们进行项目的开发。依赖项如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis</artifactId > <version > 3.5.7</version > </dependency > <dependency > <groupId > junit</groupId > <artifactId > junit</artifactId > <version > 4.13.2</version > <scope > test</scope > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.28</version > </dependency > <dependency > <groupId > log4j</groupId > <artifactId > log4j</artifactId > <version > 1.2.17</version > </dependency >
其中log4j日志的使用还需要配合配置文件log4j.xml
。我们需要将配置文件放在resources目录下,其中的内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j :configuration SYSTEM "log4j.dtd" > <log4j:configuration xmlns:log4j ="http://jakarta.apache.org/log4j/" > <appender name ="STDOUT" class ="org.apache.log4j.ConsoleAppender" > <param name ="Encoding" value ="UTF-8" /> <layout class ="org.apache.log4j.PatternLayout" > <param name ="ConversionPattern" value ="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" /> </layout > </appender > <logger name ="java.sql" > <level value ="debug" /> </logger > <logger name ="org.apache.ibatis" > <level value ="info" /> </logger > <root > <level value ="debug" /> <appender-ref ref ="STDOUT" /> </root > </log4j:configuration >
在实际使用MyBatis之前,我们先简单了解一下它的工作原理。对于持久层,我们希望它能够完成通过Java语言来操作数据库,包括增删该查操作,同时关联Java对象与数据库中的表,同时完成SQL语句的查询。
在MyBatis中,一个实体类对应一张表,类的属性对应表的不同字段,表中的一行数据对应实体类的对象。我们需要两个重要的配置文件,一个是核心配置文件,用来准备数据库连接环境所需要的相关信息,另一个是映射文件。在MyBatis中,我们期望的操作通过Mapper接口的形式来提供,我们需要创建Mapper接口,在接口中声明我们需要的操作,然后一个Mapper接口对应一个映射文件,在映射文件中,我们会给接口的每一个方法准备对应的SQL语句,这样就实现了SQL语句与Java代码的分离。在Java代码中,MyBatis会为我们的接口生成对应的实现类,在调用接口中的方法时,MyBatis会找到映射文件中对应的SQL语句进行执行,并将结果返回。
那么我们先创建核心配置文件,在官方文档中提供了如下模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?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 ="${driver}" /> <property name ="url" value ="${url}" /> <property name ="username" value ="${username}" /> <property name ="password" value ="${password}" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="org/mybatis/example/BlogMapper.xml" /> </mappers > </configuration >
我们对其进行相应的修改,主要修改驱动类、连接、用户名、密码等。这里映射文件引入路径与实际情况有关。
注意这里的核心配置文件的名称没有强制要求,我们习惯上将其命名为mybaits-config.xml
。核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息,存放位置为resources目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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 ="jdbc:mysql://localhost:3306/ssm_data" /> <property name ="username" value ="root" /> <property name ="password" value ="123123" /> </dataSource > </environment > </environments > <mappers > <mapper resource ="mappers/UserMapper.xml" /> </mappers > </configuration >
前面我们提到,在MyBatis中,数据库中的一张表会对应一个实体类,同时会对应一个Mapper接口,而一个Mapper接口又会对应一个映射文件,那么接下来我们就要完成这些资源的准备。
先创建对应的实体类,这里我们的表为user,可以创建一个实体类User,其中的属性就是表中的字段。将实体类中的相关方法都进行实现,包括无参构造,有参构造,属性的getter和setter方法,toString方法等。
之后创建Mapper接口。在接口中,我们声明的方法后续都可以进行使用。这里我们声明一个insert方法,用于向表格中插入一条记录。
1 2 3 public interface UserMapper { int insertUser () ; }
然后我们需要创建映射文件,映射文件也放在resources目录下。我们同样可以参考官方文档中映射文件的书写方式:
1 2 3 4 5 6 7 8 9 <?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 ="org.mybatis.example.BlogMapper" > <select id ="selectBlog" resultType ="Blog" > select * from Blog where id = #{id} </select > </mapper >
在映射文件中,我们需要先指定其中的namespace,这表示该映射文件与哪个Mapper接口对应。然后,我们需要指定每个接口方法对应的SQL语句,例如这里的接口中的insertUser方法,它对应的SQL语句如下所示,使用了insert标签进行包裹,并且标签的id属性指定为insertUser。
1 2 3 4 5 6 7 8 9 10 <?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.syh.mapper.UserMapper" > <insert id ="insertUser" > insert into users values(null, 'admin', '123123', 18, '女', '123456@haha.com') </insert > </mapper >
一般情况下,我们将映射文件命名为表所对应的实体类类名+Mapper.xml
,表示一个映射文件对应一个实体类,对应一张表的操作。
MyBatis中可以面向接口操作数据,但是其中要保证两个一致:
Mapper接口中的全类名和映射文件的namespace保持一致
Mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致
至此,我们就已经做好了准备工作,可以书写方法进行测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml" );SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder ();SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession(true );UserMapper userMapper = sqlSession.getMapper(UserMapper.class);int result = userMapper.insertUser(); System.out.println("result: " + result);
其他操作
上面我们提供了简单的插入操作,当然我们还可以提供其他简单的增删查改的操作。增加操作的时候,需要在接口中声明对应的方法,同时在映射文件中指定对应的标签以及标签内的SQL语句。
在接口中分别增加删除操作、修改操作、查询一行以及查询多行的操作:
1 2 3 4 5 6 7 8 9 10 11 public interface UserMapper { int insertUser () ; int deleteUser () ; int updateUser () ; User getUser () ; List<User> getUserList () ; }
映射文件中需要提供对应的SQL语句,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <mapper namespace ="com.syh.mapper.UserMapper" > <insert id ="insertUser" > insert into users values (null, 'admin', '123123', 18, '女', '123456@haha.com') </insert > <delete id ="deleteUser" > delete from users where id = 1 </delete > <update id ="updateUser" > update users set password = 'normal' where username = 'normal' </update > <select id ="getUser" resultType ="com.syh.bean.User" > select * from users where id = 3 </select > <select id ="getUserList" resultType ="com.syh.bean.User" > select * from users </select > </mapper >
在查询操作select中,我们需要指定属性resultType或者resultMap,用来设置实体类和数据库表中记录的映射关系。两种映射只能设置其中一种:
核心配置文件
在入门案例中,我们使用的核心配置文件中只有一些最基本的内容,完整的核心配置文件,其中还提供了其他相关的标签,这里进行相关说明。
在核心配置文件中提供有多种标签,但是这些标签必须按照固定的顺序进行书写,具体顺序如下:properties
、settings
、typeAliases
、typeHandlers
、objectFactory
、objectWrapperFactory
、reflectorFactory
、plugins
、environments
、databaseIdProvider
、mappers
。这里先介绍一些常见的标签,其他标签后续使用到的时候再进行介绍。
properties
1 <properties resource ="jdbc.properties" > </properties >
properties
标签允许我们引入配置文件。在引入过后,properties文件中的值可以在核心配置文件中进行使用,使用${key}
的方式来访问value。
typeAliases
1 2 3 4 5 <typeAliases > <typeAlias type ="com.syh.bean.User" alias ="abc" > </typeAlias > <typeAlias type ="com.syh.bean.User" > </typeAlias > <package name ="com.syh.bean" /> </typeAliases >
typeAlias
标签允许我们设置类型的别名。
基本的使用方式是在type中提供需要设置别名的类型,同时在alias中提供别名。如果不设置该属性,则该类型会使用默认的别名,即该类型的类名,这里默认的别名就是User,不过类名不区分大小写。
另一种方式是以包的形式引入别名,在name中提供包的路径。该包下的所有类型都会被设置默认的类型别名,即类名且不区分大小写
environments
1 2 3 4 5 6 7 8 9 10 11 <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.username}" /> <property name ="password" value ="${jdbc.password}" /> </dataSource > </environment > </environments >
在environments
标签中会配置项目的环境,其中可以配置多个环境,但是生效的只会有一个,由default属性来指定。
具体的环境由标签environment
来指定。在该标签中,我们需要设置事务管理方式以及数据源。
事务管理方式对应标签transactionManager
,其中的需要提供type属性。type属性只有两个可选值,分别是JDBC和MANAGED:
JDBC:表示当前环境中,执行SQL时使用的是JDBC中原生的事务管理方式,事务的提交或者回滚需要手动处理
MANAGED:表示MyBatis被管理,例如Spring等
数据源的配置对应标签dataSource
,其中需要提供数据源的属性type,可选值有POOLED、UNPOOLED以及JNDI:
POOLED:表示使用数据库连接池来缓存数据库连接
UNPOOLED:表示不使用数据库连接池
JNDI:表示使用上下文中的数据源
同时数据源中还需要配置连接数据库的驱动、连接地址、用户名和密码等。
mappers
1 2 3 4 <mappers > <mapper resource ="mappers/UserMapper.xml" /> <package name ="com.syh.mapper" /> </mappers >
mappers
标签中引入对应的映射文件。我们可以通过mapper
标签的方式引入单个映射文件,在resource属性中指定对应的路径。另一种方式是以包为单位引入映射文件,使用package
标签。引入后,包下所有的映射文件都会被引入,不过使用包引入需要满足下面的要求:
Mapper接口所在的包要和映射文件所在的包一致
Mapper接口要和映射文件的名称一致
所在的包一致,即目录结构相同。在IDEA中,则表现为在resouces目录下创建对应的目录结构来存放映射文件。在项目加载之后,java目录和resources目录下的内容会被放在同一个目录下。