1 简介
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。
开发效率:Hibernate>Mybatis>JDBC
运行效率:JDBC>Mybatis>Hibernate
2 快速入手
依赖导入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependencies>
<!-- mybatis依赖 -->
<dependency>
<groupId> org.mybatis</groupId>
<artifactId> mybatis</artifactId>
<version> 3.5.11</version>
</dependency>
<!-- MySQL驱动 mybatis底层依赖jdbc驱动实现,本次不需要导入连接池,mybatis自带! -->
<dependency>
<groupId> mysql</groupId>
<artifactId> mysql-connector-java</artifactId>
<version> 8.0.25</version>
</dependency>
<!--junit5测试-->
<dependency>
<groupId> org.junit.jupiter</groupId>
<artifactId> junit-jupiter-api</artifactId>
<version> 5.3.1</version>
</dependency>
</dependencies>
准备Mapper接口和MapperXML文件
1
2
3
4
5
6
/*Mapper接口
*/
public interface EmployeeMapper {
Employee selectEmployee ( Integer empId );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
<!--MapperXML文件-->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace等于mapper接口类的全限定名 -->
<mapper namespace= "com.Xxx.EmployeeMapper" >
<!-- id对应方法名 resultType对应返回值类型-->
<select id= "selectEmployee" resultType= "com.Xxx.Employee" >
select emp_id empId,emp_name empName, emp_salary empSalary from
t_emp where emp_id = #{empId}
</select>
</mapper>
配置文件
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
31
32
33
<!-- Mybatis配置文件 -->
<?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表示配置Mybatis的开发环境,可以配置多个环境,在众多具体环境中,使用default属性指定实际运行时使用的环境。default属性的取值是environment标签的id属性的值。 -->
<environments default= "development" >
<!-- environment表示配置Mybatis的一个具体的环境 -->
<environment id= "development" >
<!-- Mybatis的内置的事务管理器 -->
<transactionManager type= "JDBC" />
<!-- 配置数据源 -->
<dataSource type= "POOLED" >
<!-- 建立数据库连接的具体信息 -->
<property name= "driver" value= "com.mysql.cj.jdbc.Driver" />
<property name= "url" value= "jdbc:mysql://localhost:3306/mybatis-example" />
<property name= "username" value= "root" />
<property name= "password" value= "root" />
</dataSource>
</environment>
</environments>
<mappers>
<!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
<!-- mapper标签:配置一个具体的Mapper映射文件 -->
<!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
<!-- 对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
<mapper resource= "mappers/EmployeeMapper.xml" />
</mappers>
</configuration>
运行测试
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
31
32
/**
*测试类
*/
public class MyBatisTest {
@Test
public void testSelectEmployee () throws IOException {
// 1.创建SqlSessionFactory对象
// ①声明Mybatis全局配置文件的路径
String mybatisConfigFilePath = "mybatis-config.xml" ;
// ②以输入流的形式加载Mybatis配置文件
InputStream inputStream = Resources . getResourceAsStream ( mybatisConfigFilePath );
// ③基于读取Mybatis配置文件的输入流创建SqlSessionFactory对象
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder (). build ( inputStream );
// 2.使用SqlSessionFactory对象开启一个会话
SqlSession session = sessionFactory . openSession ();
// 3.根据EmployeeMapper接口的Class对象获取Mapper接口类型的对象(动态代理技术)
EmployeeMapper employeeMapper = session . getMapper ( EmployeeMapper . class );
// 4. 调用代理类方法既可以触发对应的SQL语句
Employee employee = employeeMapper . selectEmployee ( 1 );
System . out . println ( "employee = " + employee );
// 4.关闭SqlSession
session . commit (); //提交事务 [DQL不需要,其他需要]
session . close (); //关闭会话
}
}
3 具体参数
3.1 SQL传参
实际开发中,能用#{}实现的,肯定不用${}。
特殊情况: 动态的不是值,是列名或者关键字,需要使用${}拼接
1
2
@Select ( "select * from user where ${column} = #{value}" )
User findByColumn ( @Param ( "column" ) String column , @Param ( "value" ) String value );
3.2 数据输入
1
Employee selectEmployee ( Integer empId );
1
2
3
<select id= "selectEmployee" resultType= "com.atguigu.mybatis.entity.Employee" >
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId}
</select>
1
int insertEmployee ( Employee employee );
1
2
3
<insert id= "insertEmployee" >
insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})
</insert>
Mybatis会根据#{}中传入的数据,加工成getXxx()方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到#{}解析后的问号占位符这个位置。
1
int updateEmployee ( @Param ( "empId" ) Integer empId , @Param ( "empSalary" ) Double empSalary );
1
2
3
<update id= "updateEmployee" >
update t_emp set emp_salary=#{empSalary} where emp_id=#{empId}
</update>
1
int updateEmployeeByMap ( Map < String , Object > paramMap );
1
2
3
<update id= "updateEmployeeByMap" >
update t_emp set emp_salary=#{empSalaryKey} where emp_id=#{empIdKey}
</update>
3.3 数据输出
1
2
3
<select id= "selectEmpCount" resultType= "int" >
select count(*) from t_emp
</select>
resultType = “全限定符或者别名,如果是返回集合类型,写范型类型即可”
1
Employee selectEmployee ( Integer empId );
1
2
3
<select id= "selectEmployee" resultType= "Xxx.Employee" >
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}
</select>
通过给数据库表字段加别名,让查询结果的每一列都和Java实体类中属性对应起来。
或者开启驼峰映射。
1
2
3
<settings>
<setting name= "mapUnderscoreToCamelCase" value= "true" />
</settings>
1
Map < String , Object > selectEmpNameAndMaxSalary ();
1
2
3
<select id= "selectEmpNameAndMaxSalary" resultType= "map" >
SQL
</select>
1
List<Employee> selectAll();
1
2
3
4
<select id= "selectAll" resultType= "Employee" >
select emp_id empId,emp_name empName,emp_salary empSalary
from t_emp
</select>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!--主键自增-->
<!-- useGeneratedKeys属性字面意思就是“使用生成的主键” -->
<!-- keyProperty属性可以指定主键在实体类对象中对应的属性名,Mybatis会将拿到的主键值存入这个属性 -->
<insert id= "insertEmployee" useGeneratedKeys= "true" keyProperty= "empId" >
insert into t_emp(emp_name,emp_salary)
values(#{empName},#{empSalary})
</insert>
<!-- 主键非自增 -->
<insert id= "insertUser" parameterType= "User" >
<!-- keyProperty 属性来指定查询到的 UUID 赋值给对象中的 id 属性-->
<selectKey keyProperty= "id" resultType= "java.lang.String"
order= "BEFORE" >
SELECT UUID() as id
</selectKey>
INSERT INTO user (id, username, password)
VALUES (
#{id},
#{username},
#{password}
)
</insert>
3.4 多表映射
对一:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<resultMap id= "selectOrderWithCustomerResultMap" type= "order" >
<!-- 先设置Order自身属性和字段的对应关系 -->
<!-- 使用id标签设置主键列和主键属性之间的对应关系 -->
<!-- column属性用于指定字段名;property属性用于指定Java实体类属性名 -->
<id column= "order_id" property= "orderId" />
<result column= "order_name" property= "orderName" />
<!-- 使用association标签配置“对一”关联关系 -->
<!-- property属性:在Order类中对一的一端进行引用时使用的属性名 -->
<!-- javaType属性:一的一端类的全类名 -->
<association property= "customer" javaType= "customer" >
<!-- 配置Customer类的属性和字段名之间的对应关系 -->
<id column= "customer_id" property= "customerId" />
<result column= "customer_name" property= "customerName" />
</association>
</resultMap>
<!-- Order selectOrderWithCustomer(Integer orderId); -->
<select id= "selectOrderWithCustomer" resultMap= "selectOrderWithCustomerResultMap" >
SELECT order_id,order_name,c.customer_id,customer_name
FROM t_order o
LEFT JOIN t_customer c
ON o.customer_id=c.customer_id
WHERE o.order_id=#{orderId}
</select>
对多:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- 配置resultMap实现从Customer到OrderList的“对多”关联关系 -->
<resultMap id= "selectCustomerWithOrderListResultMap"
type= "customer" >
<!-- 映射Customer本身的属性 -->
<id column= "customer_id" property= "customerId" />
<result column= "customer_name" property= "customerName" />
<!-- collection标签:映射“对多”的关联关系 -->
<!-- property属性:在Customer类中,关联“多”的一端的属性名 -->
<!-- ofType属性:集合属性中元素的类型 -->
<collection property= "orderList" ofType= "order" >
<!-- 映射Order的属性 -->
<id column= "order_id" property= "orderId" />
<result column= "order_name" property= "orderName" />
</collection>
</resultMap>
<select id= "selectCustomerWithOrderList" resultMap= "selectCustomerWithOrderListResultMap" >
SELECT c.customer_id,c.customer_name,o.order_id,o.order_name
FROM t_customer c
LEFT JOIN t_order o
ON c.customer_id=o.customer_id
WHERE c.customer_id=#{customerId}
</select>