MyBatis
1. 简介
MyBatis是一个基于Java的持久化成框架。
MyBatis支持定制化SQL。
MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据可以中的记录。
MyBatis对于开发人员来说,核心SQL还是需要自己优化。
SQL和Java编码分开,功能边界清晰,一个专注业务,一个专注数据。
耦合性低方便后期维护。
2. HelloWorld
1)导入jar包和log4j的jar包还有log4j的xml配置文件
2)在数据库中创建MyBatis的表并在modul中创建Employee类
package com.atguigu.mybatis.mapper;
import com.atguigu.mybatis.entities.Employee;
public interface EmployeeMapper {
Employee getEmployeeById(Integer id);
void insertEmployee(Employee employee);
}
3)创建接口,增删改查
4)创建MyBatis的sql映射文件
①参考MyBatis官方文档创建EmployeeMapper.xml映射文件
②完成两个绑定
a)标签中的namespace属性必须设置为Mapper接口的全类名
b)Mapper映射文件中的增删改查标签的id必须指定成Mapper接口中的方法名
<?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属性设置为接口的全类名-->
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
<!--
id属性:设置为接口中的方法名
resultType属性:设置为方法的返回值的类型的全类名
resultMap属性:方法的返回值是Map 要么是type要么是map
-->
<select id="getEmployeeById" resultType="com.atguigu.mybatis.entites.Employee">
select id,last_name,email,salary,dept_id deptId
from employees
where id = #{id}
</select>
</mapper>
5)创建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 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>
6)创建测试文件
public class MyBatisTest{
// 1.获取SqlSessionFactory
public SqlSessionFactory getSqlSessionFactory() throw IOException{
// 2.设置全局配置文件的路径
String resource = "mybatis-config.xml";
// 3.将类路径下的全局配置文件读成输入流
Inputstream inputStream = Resources.getResourceAsStream(resource);
// 4.构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().bulid(inputStream);
return sqlSessionFactory;
}
/*
测试HelloWorld
*/
@Test
public void testHelloWorld() throw IOException{
// 5.获取SqlSessionFactory
SqlSessionFactory sqlSqlSessionFactory = getSqlSessionFactory();
// 6.获取sqlSessionFactory,相当于原来的Connection
SqlSession sqlSession = sqlSessionFactory.openSession();
try{
// 7.获取Mapper对象
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
// 8.调用EmployeeMapper中查询一个员工的方法
Emplpyee employeeById = employeeMapper.getEmployeeById(1);
System.out.println("emplpyeeById = "+employeeById);
}finally{
// 9.关闭sqlSession
sqlSession.close();
}
}
}
3. 增删改查
获取SqlSessionFactory
public SqlSessionFactory getSqlSessionFactory() throws IOException {
// 2.设置全局配置文件的路径
String resource = "mybatis-config.xml";
// 3.将类路径下的全局配置文件读成输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 4.构建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
在EmployeeMapper的配置文件中写入增删改查的语句和方法
<!--查找-->
<select id="getEmployeeById" resultType="com.atguigu.mybatis.entities.Employee">
select id,last_name lastName,email,salary,dept_id deptId
from employees
where id = #{id}
</select>
<!--添加
parameterType属性:指定方法中的入参类型也可以不指定,MyBatis会自动推断
useGeneratedKeys属性:设置是和否获取数据库中的主键值
注意;数据库必须支持自增主键
keyProperty属性:设置获取的主键值赋给POJO的那个属性
-->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="id">
insert into employees(last_name,email,salary,dept_id)
values (#{lastName},#{email},#{salary},#{deptId})
</insert>
<!--删除-->
<delete id="deleteEmployeeById">
delete from employees where id = #{id}
</delete>
<!--更新-->
<update id="updateEmployee">
update employees set
last_name = #{lastName},
email = #{email},
salary = #{salary},
dept_id = #{deptId}
where id = #{id}
</update>
在测试类中首先要获取SqlSessionFactory
再调用SqlSessionFactory的openSession方法
获取Mapper对象,利用Mapper对象调用Mapper对象中的增删改查的方法
增删改需要手动提交sqlSeesion.commin()
最后在finally块中关闭sqlSession
sqlSession.close();
3. MyBatis全局配置文件
1)properties标签
可以引入外部的属性文件配置数据源
resource属性:引入类路径下的属性文件
url属性:引入网络或者磁盘上的属性文件
<propertirs resource="db.properties">
<property name="password" value="root2"/>
</propertirs>
2) ★settings标签
settings标签是用来设置MyBatis中的重要配置,它们会改变MyBatis的运行行为。
<settings>
<!--开启驼峰命名自动映射-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3)typeAliases标签
用来给POJO类设置别名
通过子标签typeAlias设置别名
type属性:指定要起别名的全类名
alias属性:指定别名,如果不指定,默认首字母小写,别名不区分大小写
通过子标签package批量设置别名
name属性:name属性:指定包名,会该包下所有的类都指定了别名
<typeAliases>
<!-- <typeAlias type="com.atguigu.mybatis.entities.Employee" alias="employee"></typeAlias>-->
<package name="com.atguigu.mybatis.entities"/>
</typeAliases>
4)typeHandlers标签
用来配置类型处理器
<typeHandlers>
<typeHanlder handler="配置自定义的类型处理器的全类名"></typeHanlder>
</typeHandlers>
5)plugins标签
用来配置插件,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行
<plugins>
<plugin interator="配置插件的全类名"></plugin>
</plugins>
6)environments标签
环境配置:MyBatis可以配置多种环境,比如开发测试和生产环境都需要有不同的配置
每个环境都是用一个environment标签进行配置并通过id指定唯一标识符
<environments default="developent">
<!--开发环境-->
<environment id="developent">
<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>
<!--生产环境-->
<environment id="online">
<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>
7)★databaseIdProvider标签
用来给不同数据库厂商指定别名
<databaseIdProvider>
<property name="MySql" value="mysql"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
8)★mappers标签
用来注册SQL映射文件(Mapper映射文件)
mapper标签每写一次就需要注册一次,如果是package属性就不需要反复注册
<mappers>
<mapper resource="com/atguigu/mybatis/dao/Employee.xml"/>
</mappers>
通过子标签mapper注册Mapper映射文件
resource属性:指定类路径下的映射文件
url属性:指定网络或者磁盘上的映射文件
class属性:通过指定接口全类名注册对应的映射文件
使用该属性进行配置有以下要求:
映射文件必须与接口通报同名或者使用注解的方式写sql语句
通过子标签package批量注册Mapper映射文件
name属性:指定包名
使用该属性有以下要求:
映射文件必须与接口同包同名或者使用注解的方式写sql语句
<mappers>
<mapper resource="com.atguigu/mybatis/mapper/EmployeeMapper.xml"/>
<mapper class="com.aguigu.mybatis.mapper.EmployeeMapper"/>
<package name="com.atguigu.mybatis.mapper"/>
</mappners>
4. MyBatis映射文件
MyBatis的映射文件是最强大的,与JDBC代码进行对比,省掉了将近95%的代码。
1)MyBatis的CRUD
select
Mapper接口方法
Employee getEmployeeById(Integer id);
Mapper映射文件
<select id="getEmployeeById" resultType="employee" dataBaseId="mysql">
select id,last_Name lastName,email,salary,dept_id
from employees
where id=#{id}
</select>
id属性设置为接口的方法名
resultType属性:设置为方法的返回值的类型的全类名
resultMap属性(二选一):自己映射
flushCache:清理缓存(增删改)默认值false
insert
Mapper接口方法
void insertEmployee(Employee employee);
Mapper映射文件
parameterType属性:指定方法的入参的类型,也可以不指定,MyBatis会自动推断
useGeneratedKeys属性:设置是否获取数据库中生成的主键值,注意:数据库必须支持自增
keyProperty属性:设置获取的主键值赋给POJO的那个属性
<insert>
insert id="insertEmployee" useGeneratedKeys="true" keyProperty="id">
insert into employees(last_name,email,salary,dept_id)
values (#{lastName},#{email},#{salary},#{deptId})
</insert>
update
Mapper接口方法
void updateEmployee(Employee employee);
Mapper映射文件
<!--更新-->
<update id="updateEmployee">
update employees set
last_name = #{lastName},
email = #{email},
salary = #{salary},
dept_id = #{deptId}
where id = #{id}
</update>
delete
Mapper接口方法
Employee deleteEmployeeById(Integer id)
Mapper映射文件
<!--删除-->
<delete id="deleteEmployeeById">
delete from employees where id = #{id}
</delete>
2)参数处理:参数传递
①单个参数
当入参是单个参数,基本类型,包装类型,字符串类型时,MyBatis不做任何处理,填充占位符时,key可以任意指定
如:#{任意指定key}
②多个参数
当入参是多个参数时,MyBatis会封装到一个Map中,此时填充的占位符的key是arg0,arg1,arg2…或者param1,param2…
如:#{arg0}或#{param1}
我们也可以在入参前面添加@Param主键指定key
③传入Map
我们可以将多个参数放在一个Map中传入,此时填充占位符时的key就是Map中指定的Key
如:#{Map中的key}
④入参是POJO
如果传入的多个参数可以封装成POJO对象,那么可以直接传入POJO对象,此时填充占位符的key是POJO的属性名。
如:#{POJO类的属性}
⑤入参为TO(Transfer Object,传输对象)
如果传入的多个参数不可以封装成POJO对象,但是经常使用,可以封装成一个TO
⑥Collection/Array
会被MyBatis封装成一个map传入, Collection对应的key是collection,Array对应的key是array。如果确定是List集合,key还可以是list。
<!--根据员工的姓名和邮箱查询-->
<select id="getEmployeeByLastNameAndEmail" resultType="employee">
select id,last_name,email,salary,dept_id
from employees
where last_name = #{lastName} and email = #{email}
</select>
/*
测试根据员工姓名和邮箱获取员工对象信息
*/
@Test
public void testGetEmployeeByLastNameAndEmail() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = employeeMapper.getEmployeeByLastNameAndEmail("Jack", "roselove@gmail.com");
System.out.println("employee = " + employee);
}finally {
sqlSession.close();
}
}
3)select查询的几种情况
查询所有员工返回List
List<Employee> getEmployees();
<!--
查询所有员工返回List
resultType属性:如果返回的是List,那么该值就是List中数据的值
-->
<select id="getEmployees" resultType="com.atguigu.mybatis.entities.Employee">
select id,last_name,email,salary,dept_id
from employees
</select>
查询一个员工返回Map,数据库中字段名为key,字段值为value
Map<String,Object> getEmployeeById(Integer id);
<!--查询所有员工返回Map-->
<select id="getEmployeeById" resultType="map">
select id,last_name,email,salary,dept_id
from employees
where id = #{id}
</select>
查询所有员工返回Map
@MapKey("last_name")// 需要指定将数据库中的哪个字段指定为key
Map<String,Object> getEmployeesByMap();
<!--查询所有员工返回Map-->
<select id="getEmployeesByMap" resultType="map">
select id,last_name,email,salary,dept_id
from employees
</select>
{Mahuateng={last_name=Mahuateng, id=3, salary=10000.0, dept_id=3, email=mahuateng@qq.com}, Jack={last_name=Jack, id=1, salary=52000.0, dept_id=1, email=roselove@gmail.com}}
4)高级结果集映射 (映射主键,映射其他列)
级联属性赋值
<select id="getEmployeeByIdContainsDept" resultMap="myEmp">// 用resultMap需要自己定义高级结果集映射
SELECT e.*,d.id d_id,d.name d_name
FROM employees e
LEFT JOIN departments d
ON e.dept_id = d.id
WHERE e.id = #{id}
</select>
自定义高级结果集映射
需要映射employee,所以要引入employee的全类名
column属性:指定数据库中的字段名
property属性:指定POJO的属性名
<resultMap id="myEmp" type="com.atguigu.mybatis.entities.Employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="email" property="email"></result>
<result column="salary" property="salary"></result>
<!--通过级联属性映射部门信息-->
<result column="d_id" property="dept.id"></result>
<result column="d_name" property="dept.name"></result>
</resultMap>
association标签
通过association标签映射部门信息
property属性:要映射属性的属性名
java-type属性:要映射属性的类型
employee中的映射与级联属性相同与dept与级联属性赋值不同
<association property="id" java-type="com.atguigu.mybatis.entities.Department">
<!--映射主键-->
<id column="d_id" property="id"></id>
<!--映射其他列-->
<result column="d_name" property="name"></result>
</association>
association标签:分步查询
通过分步查询映射部门信息
1.通过员工id查询员工信息
2.根据员工部门id查询部门信息
3.将部门信息设置到员工中(需要查询两条sql,一条sql查员工,一条sql查部门)
通过association标签分步查询映射部门信息
property属性:设置要映射的属性名
select属性:设置要映射哪个接口下的哪个方法映射部门信息(在这里需要调用DepartmentMapper标签下的getDepartmentById方法)
coulumn属性:设置将哪个字段传入到select属性中指定的方法
<association property="dept" select="com.atguigu.mybatis.mapper.DepartmentMapper.getDepartmentById"
column = "{d_id = dept_id}"></association>
分步查询延迟加载
在mybatis-config的标签中设置
<settings>
<!--开启驼峰命名法-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--设置加载的数据是按需加载的-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
在association标签中设置fetchType属性
<association property="dept" select="com.atguigu.mybatis.mapper.DepartmentMapper.getDepartmentById"
column = "dept_id" fetchType="lazy"></association>
在进行分步查询的时候可以查询其他属性
String lastName = employeeMapper.getEmployeeByIdContainsDeptByStep(1).getLastName();
System.out.println("lastName = " + lastName);
System.out.println("===================================");
Double salary = employeeMapper.getEmployeeByIdContainsDeptByStep(3).getSalary();
System.out.println("salary = " + salary);
lastName = Jack
===================================
DEBUG 04-08 14:51:03,640 ==> Preparing: select id,last_name,email,salary,dept_id from employees where id = ? (BaseJdbcLogger.java:137)
DEBUG 04-08 14:51:03,640 ==> Parameters: 3(Integer) (BaseJdbcLogger.java:137)
DEBUG 04-08 14:51:03,642 <== Total: 1 (BaseJdbcLogger.java:137)
salary = 10000.0
collection分步查询
5. 动态SQL
动态SQL是Mybatis最强大的特征之一。极大的简化了我们拼装SQL的操作。
if-where
<select id="getEmployeeByConditionIf" resultType="com.atguigu.mybatis.entities.Employee">
select id,last_name,email,salary
from employees where
<if test="id != null">
id = #{id} and
</if>
<if test="lastName != null && lastName != "" ">
last_Name = #{lastName} and
</if>
<if test="email != null and email.trim() != '' ">
email = #{email} and
</if>
<if test="salary != null">
salary = #{salary} and
</if>
</select>
可能会出现的问题
问题一:当值为null的时候,sql语句会出现异常
解决方案一:在最前面添加where 1 = 1(在开发中不常用)
解决方案二:嵌套where标签
问题二:当每个条件后面有and或or的时候,最后一个条件不满足会导致sql语句异常
解决方案一:在整个sql语句后面添加恒等式
解决方案二:使用trim标签
trim标签
prefix属性:添加前缀
prefixOverrides属性:删除前缀
suffix:添加后缀
suffixOverrides:删除后缀
<select id="getEmployeeByConditionIf" resultType="com.atguigu.mybatis.entities.Employee">
select id,last_name,email,salary
from employees
<trim prefix="where" suffixOverrides="and">
<if test="id != null">
id = #{id} and
</if>
<if test="lastName != null && lastName != "" ">
last_Name = #{lastName} and
</if>
<if test="email != null and email.trim() != '' ">
email = #{email} and
</if>
<if test="salary != null">
salary = #{salary} and
</if>
</trim>
</select>
choose标签
相当于if…else if… else…
子标签when和otherwise标签需要在choose标签中使用。
when标签只要有一条满足就不再执行
<select id="getEmployeeByConditionChoose" resultType="com.atguigu.mybatis.entities.Employee">
select id,last_name,email,salary
from employees where
<choose>
<when test="id != null">
id = #{id}
</when>
<when test="lastName!= null">
last_name = #{lastName}
</when>
<when test="email != null">
email = #{email}
</when>
<otherwise>
salary = #{salary}
</otherwise>
</choose>
</select>
set标签
<!--set标签-->
<update id="updateEmployeeByConditionSet">
update employees
<set>
<if test="lastName != null">
last_name = #{lastName},
</if>
<if test="email != null">
email = #{email},
</if>
<if test="salary != null">
salary = #{salary}
</if>
</set>
where id = #{id}
</update>
forEach标签
sql标签
SSM整合
Spring与SpringMVC整合**!!!!!标注解@Service@Controller**
- 在WEB-INF下创建lib文件夹导入jar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcBMi1BM-1618309475135)(C:\Users\可爱的西西里亚\AppData\Roaming\Typora\typora-user-images\image-20210409180604430.png)]
-
创建controller、service、entities、mapper的包
-
为spring配置bean文件
-
引入druid.properties文件
-
配置自动扫描的包,不扫描Controller
-
引入外部属性文件,配置数据源属性
-
配置事务管理器,配置数据源属性
-
开启事务支持,是tx的
-
配置web.xml
-
配置springmvc.xml
-
创建service
-
在views中引入list.jsp
-
创建mapper和Mapper.xml
employees
last_name = #{lastName},
email = #{email},
salary = #{salary}
where id = #{id}
### forEach标签
### sql标签
# SSM整合
## Spring与SpringMVC整合**!!!!!标注解@Service@Controller**
* 在WEB-INF下创建lib文件夹导入jar包
[外链图片转存中...(img-tcBMi1BM-1618309475135)]
* 创建controller、service、entities、mapper的包
* 为spring配置bean文件
* 引入druid.properties文件
* 配置自动扫描的包,不扫描Controller
* 引入外部属性文件,配置数据源属性
* 配置事务管理器,配置数据源属性
* 开启事务支持,是tx的
* 配置web.xml
* 配置springmvc.xml
* 创建service
* 在views中引入list.jsp
* 创建mapper和Mapper.xml