mybatis它内部封装了jdbc,简化了原始持久层操作每次都要去处理加载驱动、创建连接、创建statement等繁杂的过程;
上面这些操作,JDBCTemplate工具类也实现了,为什么JDBCTemplate不叫框架,而是工具类呢?原因是工具类只是对操作的一些封装,对于更多的细节它并没有去处理和提供解决方案。
定制化SQL、存储过程、高级映射
相较jdbc,SQL代码夹杂在Java代码中耦合度高不易维护
相较Hibernate和JPA
自动生成SQL,不容易做特殊优化
反射太多,导致数据库性能下降
mybatis的简单搭建
- 打开idea
- 创建一个空的maven项目,导入mybatis和数据库MySQL的maven依赖
- 配置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">
<!-- mybatis的主配置文件 -->
<configuration>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
<mappers>
<mapper resource="com/lwlong/dao/IUserDao.xml"/>
</mappers>
</configuration>
顺便配置一下日志
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
- 创建映射文件mapper
<?xml version="1.0" encodeing="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lwlong.dao.IUserDao">
<!--查询所有用户-->
<select id="findAll" resultType="com.lwlong.entity.User">
select * from user
</select>
</mapper>
- MyBatis的使用案例
public static void main(String[] args)throws Exception {
//1.读取配置文件
InputStream is = Resource.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
//3.使用工厂生产SqlSession对象
SqlSession sqlSession = factory.openSession();
//4.使用SqlSession创建Dao(Mapper)接口的代理对象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println(user);
}
//6.释放资源
sqlSession.close();
is.close();
}
MyBatis细节处理解决方案
MyBatis获取参数的几种方式
1、通过#{}方式,原理是占位符的形式,可以防止SQL注入,替换的参数默认使用''包围
2、通过${}方式,原理字符串拼接形式,存在SQL注入风险,传入的参数是什么就直接替换到SQL语句中
3、Mapper的代理实现类,mapper接口方法的参数,底层对传入的参数是以Map的形式封装,默认有键为parma1,parma2 ...;
在mapper.xml文件中sql的#{}、${}通过属性名获取,①使用java对象传递,对象的属性;②使用多个参数,mapper接口中参数设置@Param注解value值;③通过位置形式获取;④通过map
通过${}方式,动态替换表名
在
全局配置处理字段名和属性名不一致的情况
在mybatis-config.xml配置文件中添加如下配置
<settings>
<!--将下划线映射为驼峰->
<setting name="mapUnderscoreTocamelcase" value="true"/>
</settings>
使用resultMap处理属性名与字段名不一致的情况
在Mapper.xml映射SQL字段,使用
<resultMap id="empResultMap" type="com.xxx.Emp"><!--如果配置了mybatis全局别名配置,可以直接写默认简称别名-->
<result property="empId" column="emp_id" jdbcType="int"/>
<result property="empName" column="emp_name" jdbcType="String"/>
<result property="age" column="age" jdbcType="int"/>
</resultMap>
使用association来处理封装级联对象属性
<association property="dept" javaType="Dept">
<id column="dept_id" property="deptId"></id>
<result column="dept_name" property="deptName"></result>
</ association>
> MyBatis处理多对一的映射关系查询,使用分步的查询方式;缺点:写的查询语句多;优点:可以延迟加载
> 必须在全局配置文件中设置全局配置信息
> lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
> aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载
> 此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载, fetchType="lazy(延迟加载)|eager(立即加载)"
mybatis动态SQL
Mybatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接sQL语句字符串时的痛点问题。I
标签的使用:
if
if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行
<!--List<Emp> getEmpListByCondition(Emp emp);-->
<select id="getEmpListByMoreT" resultType="Emp">
select * from t_emp where 1=1
<if test="ename != '' and ename != nu11">
and ename = #{ename}
</if>
<if test="age != '' and age != nu11">
and age = #{age}
</if>
<if test="sex != '' and sex != nu11">
and sex = #{sex}
</if>
</select>
where
where标签,可以自动生成where关键字,可以自动去除条件字段前的and关键字,不能去除条件字段后的and的关键字;
trim
trim标签属性
prefix、suffix:在标签中内容前面或后面添加指定内容
prefixOverrides、suffixOverrides:在标签中内容前面或后面去掉指定内容
<select id="getEmpListByMoreT" resultType="Emp">
select * from t_emp
<trim prefix="where" suffixoverrides="and">
<if test="ename != '' and ename != nu11">
ename = #{ename} and
</if>
<if test="age != '' and age != nu11">
age = #{age} and
</if>
<if test="sex != '' and sex != nu11">
sex = #{sex} and
</if>
</trim>
</select>
choose、when、otherwise
多条件判断组合标签,相当于java中的if...else if...else
forEach
试用在批量添加、批量删除,非常常用的标签
<!--void insertMoreEmp(@param ( " emps" ) List<Emp> emps);-->
<insert id="insertMoreEmp">
insert into t_emp values
<foreach collection="emps" item="emp" separator=",">
(null,#{emp. empName} ,#{emp.age} ,#{emp.gender},null)
</foreach>
</insert>
<!--void deleteMoreEmp(@param ( "empIds" ) Integer[] empIds);-->
<delete id="deleteMoreEmp">
delete from t_emp where
<foreach collection="empIds" item="empId" separator="or">
emp_id = #{empId}
</foreach>
</delete>
sql
sql标签,定义一个sql片段,例如:在mybatis中建议不要写select * ...因为在执行时还是要去查找一遍具有的字段;也可以定义存储过程;
<sql id="empcolumns">
emp_id,emp_name,age,gender,dept_id
</sql>
<!--然后在select标签中,写查询语句时,使用<include refid="片段id">标签引入sql片段-->
<select id="getEmpListByMoreT" resultType="Emp">
select <include refid="empcolumns"></include> from t_emp
</select>
MyBatis的缓存
MyBatis的一级缓存(默认开启的)
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
使一级缓存失效的四种情况:|
1)不同的SqlSession对应不同的一级缓存
2)同一个SqlSession但是查询条件不同
3)同一个SqlSession两次查询期间执行了任何一次增删改操作
4)同一个SqlSession两次查询期间手动清空了缓存
@Test
public void testGetEmpById(){
SqlSession sqlSession1 = SqlSessionUtil.getSqlSession();
CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
Emp emp1 = mapper1.getEmpById(1);
System.out.println(emp1);
Emp emp2 = mapper1.getEmpById(1);
System.out.println(emp2);
SqlSession sqlSession2 = SqlSessionUtil.getSqlSession();
CacheMapper mapper2 = sqlSession2.getMapper(CacheMapper.class);
Emp emp3 = mapper2.getEmpById(1);
System.out.println(emp3);
}
MyBatis的二级缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
二级缓存开启的条件:
a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
b>在映射文件中设置标签<cache/>
c>二级缓存必须在SqlSession关闭或提交之后有效
d>查询的数据所转换的实体类类型必须实现序列化的接口
使二级缓存失效的情况:
两次查询之间执行了任意的增剧改,会使一级和二级缓存同时失效
评论 (0)