mybatis简介
mybatis是一个半自动的持久层框架,具有轻量级,简洁,性能出色的特点。相较于hibernate框架,mybatis的运行效率相对较高,但是由于是半自动的框架,一些单表和多表查询的SQL语句得自己定义。
MyBatis基本使用
1,创建Mapper接口
- 在mapper层中创建对应的mapper接口
public interface EmployeeMapper {
//根据id查询员工对象
//根据员工的id查询员工的姓名
String queryNameById(Integer id);
// 根据员工的id查询员工的工资
Double querysalaryById(Integer id);
//返回单个实体类型
Employee queryById(Integer id);
//查询部门的最高工资和评价工资
Map<String,Object> selectemployeeNameAndMaxsalary() ;
//查询工资高于传入值的员工的姓名
List<String> queryNamesBysalary(Double salary);
//查询全部的员工信息
List<Employee> queryAll();
//员工插入
int insertEmp(Employee employee);
}
- 写对应mapper接口的实现(编写配置文件)
<?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="base.mapper.EmployeeMapper">
<delete id="deleteById" >
delete from t_emp where emp_id = #{id}
</delete>
<!-- 返回值为单个简单类型时
resultType语法
类的全限定符号
别名简称 mybatis 提供了72种默认的别名 ,这些都是我门常用的数据类型如果没有就得自己定义 或者写类的全
限定符好
基本数据类型加_
包装数据类型 小写
集合容器类型
自己定义的类是没有别名的
自己的类如何定义别名
方案一:使用typealises标签 给类单独设置别名,比较麻烦
方案二:也可以使用包名加上《package 标签来统一定义别名 别名为类名的首字母小写
在同一配置的情况下可以在类上加上@Aliases注解来单独设置别名
-->
<select id="queryNameById" resultType="java.lang.String" >
select emp_name from t_emp where emp_id = #{id}
</select>
<select id="querySalaryById" resultType="java.lang.Double" >
select emp_salary from t_emp where emp_id = #{id}
</select>
<select id="queryById" resultType="base.pojo.Employee" >
select emp_name from t_emp where emp_id = #{id}
</select>
<!--
-->
<!--
返回值我为集合类型如何指定resultType
返回值为集合时
resultTYpe不需要指定为集合类型
只需要写为集合的泛型
mybatis的底层使用的时ibatis ibatis会调用selectone 或者 selectList方法 selectone的底层也调用了
selectList方法 使用的都是List集合
-->
<select id="queryNameBySalary" resultType="string" >
select emp_name from t_emp where emp_salary > #{salary}
</select>
<select id="queryAll" resultType="employee" >
select * from t_emp
</select>
<!--
主键回显 获取插入数据的主键
1,自增长逐渐回显
useGeneratedKeys="true"
设置为我们想要数据库增长的主键值
keyColumn="emp_id"
我们想要获取的主键列
keyProperty="empId
返回的主键的值要赋给哪个属性
2,非自增长类型的主键
-->
<insert id="insertEmp" useGeneratedKeys="true" keyColumn="emp_id" keyProperty="empId">
insert into t_emp (emp_name,emp_salary)
values(#{empName},#{empSalary})
</insert>
</mapper>
- 配置mapper文件到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>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<package name="base.pojo"/>
</typeAliases>
<!-- 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="hcx"/>
<property name="password" value="478016724hcx"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- Mapper注册:指定Mybatis映射文件的具体位置 -->
<!-- mapper标签:配置一个具体的Mapper映射文件 -->
<!-- resource属性:指定Mapper映射文件的实际存储位置,这里需要使用一个以类路径根目录为基准的相对路径 -->
<!-- 对Maven工程的目录结构来说,resources目录下的内容会直接放入类路径,所以这里我们可以以resources目录为基准 -->
<mapper resource="mappers/EmployeeMapper.xml"/>
<mapper resource="mappers/TeacherMapper.xml"/>
</mappers>
</configuration>
使用mybatis进行多表映射
对一映射
示例: 根据ID查询订单,以及订单关联的用户的信息!
mapper接口
public interface OrderMapper {
Order selectOrderWithCustomer(Integer orderId);
}
mapper文件编写如下:
<!-- 创建resultMap实现“对一”关联关系映射 -->
<!-- id属性:通常设置为这个resultMap所服务的那条SQL语句的id加上“ResultMap” -->
<!-- type属性:要设置为这个resultMap所服务的那条SQL语句最终要返回的类型 -->
<resultMap id="selectOrderWithCustomerResultMap" type="order">
<!-- 先设置Order自身属性和字段的对应关系 -->
<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>
对多映射
示例:查询客户和客户关联的订单信息!
mapper接口
public interface CustomerMapper {
Customer selectCustomerWithOrderList(Integer customerId);
}
mapper编写如下:
<!-- 配置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>
<!-- Customer selectCustomerWithOrderList(Integer customerId); -->
<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>
mybatis动态sql语句
if和where标签
if标签:当条件判断为真时,将sql语句片段与SQL语句进行拼接 where标签:自动去掉“标签体内前面多余的and/or
<!-- List<Employee> selectEmployeeByCondition(Employee employee); -->
<select id="selectEmployeeByCondition" resultType="employee">
select emp_id,emp_name,emp_salary from t_emp
<!-- where标签会自动去掉“标签体内前面多余的and/or” -->
<where>
<!-- 使用if标签,让我们可以有选择的加入SQL语句的片段。这个SQL语句片段是否要加入整个SQL语句,就看if标签判断的结果是否为true -->
<!-- 在if标签的test属性中,可以访问实体类的属性,不可以访问数据库表的字段 -->
<if test="empName != null">
<!-- 在if标签内部,需要访问接口的参数时还是正常写#{} -->
or emp_name=#{empName}
</if>
<if test="empSalary > 2000">
or emp_salary>#{empSalary}
</if>
<!--
第一种情况:所有条件都满足 WHERE emp_name=? or emp_salary>?
第二种情况:部分条件满足 WHERE emp_salary>?
第三种情况:所有条件都不满足 没有where子句
-->
</where>
</select>
set标签
<!-- void updateEmployeeDynamic(Employee employee) -->
<update id="updateEmployeeDynamic">
update t_emp
<!-- set emp_name=#{empName},emp_salary=#{empSalary} -->
<!-- 使用set标签动态管理set子句,并且动态去掉两端多余的逗号 -->
<set>
<if test="empName != null">
emp_name=#{empName},
</if>
<if test="empSalary < 3000">
emp_salary=#{empSalary},
</if>
</set>
where emp_id=#{empId}
<!--
第一种情况:所有条件都满足 SET emp_name=?, emp_salary=?
第二种情况:部分条件满足 SET emp_salary=?
第三种情况:所有条件都不满足 update t_emp where emp_id=?
没有set子句的update语句会导致SQL语法错误
-->
</update>
choose/when/otherwise标签
<!-- List<Employee> selectEmployeeByConditionByChoose(Employee employee) -->
<select id="selectEmployeeByConditionByChoose" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id,emp_name,emp_salary from t_emp
where
<choose>
<when test="empName != null">emp_name=#{empName}</when>
<when test="empSalary < 3000">emp_salary < 3000</when>
<otherwise>1=1</otherwise>
</choose>
<!--
第一种情况:第一个when满足条件 where emp_name=?
第二种情况:第二个when满足条件 where emp_salary < 3000
第三种情况:两个when都不满足 where 1=1 执行了otherwise
-->
</select>
foreach标签
使用示例
<!--
collection属性:要遍历的集合
item属性:遍历集合的过程中能得到每一个具体对象,在item属性中设置一个名字,将来通过这个名字引用遍历出来的对象
separator属性:指定当foreach标签的标签体重复拼接字符串时,各个标签体字符串之间的分隔符
open属性:指定整个循环把字符串拼好后,字符串整体的前面要添加的字符串
close属性:指定整个循环把字符串拼好后,字符串整体的后面要添加的字符串
index属性:这里起一个名字,便于后面引用
遍历List集合,这里能够得到List集合的索引值
遍历Map集合,这里能够得到Map集合的key
-->
<foreach collection="empList" item="emp" separator="," open="values" index="myIndex">
<!-- 在foreach标签内部如果需要引用遍历得到的具体的一个对象,需要使用item属性声明的名称 -->
(#{emp.empName},#{myIndex},#{emp.empSalary},#{emp.empGender})
</foreach>
sql标签
<!-- 使用sql标签抽取重复出现的SQL片段 -->
<sql id="mySelectSql">
select emp_id,emp_name,emp_age,emp_salary,emp_gender from t_emp
</sql>
使用sql片段
<!-- 使用include标签引用声明的SQL片段 -->
<include refid="mySelectSql"/>