Mybatis学习总结以及踩过的坑

环境:idea 2018 、Maven

非常感谢B站的楠哥

一、mybatis的作用

  • MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  • MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的POJOs(PlainOrdinary JavaObject,普通的 Java对象)映射成数据库中的记录。

二、mybatis的优缺点

sql语句与代码分离,存放于xml配置文件中:

  • 优点:便于维护管理,不用在java代码中找这些语句;
  • 缺点: JDBC方式可以用打断点的方式调试,但是Mybatis不能,需要通过log4j日志输出日志信息帮助调试,然后在配置文件中修改。

用逻辑标签控制动态SQL的拼接:

  • 优点:用标签代替编写逻辑代码;
  • 缺点:拼接复杂SQL语句时,没有代码灵活,拼写比较复杂。不要使用变通的手段来应对这种复杂的语句。

查询的结果集与java对象自动映射:

  • 优点:保证名称相同,配置好映射关系即可自动映射或者,不配置映射关系,通过配置列名=字段名也可完成自动映射。
  • 缺点:对开发人员所写的SQL依赖很强。

编写原生SQL:

  • 优点:接近JDBC,比较灵活。
  • 缺点:对SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦,比如mysql数据库编程Oracle数据库,部分的sql语句需要调整。

最重要的一点,使用的人多!公司需要!但是应为用了反射,效率会下降,所有有些公司会使用原生的jdbc

三、代理模式

mybatis主要使用基于接口的代理模式

  1. 静态代理
  2. 动态代理

在mybatis中主要使用动态代理,需要理解代理模式的主要实现方式,但在实际使用中mybatis已经帮封装好了,只需要调用一些方法就行。
代理模式在mybatis中的应用举例:
在测试类中Test:

private SqlSession session;
    /**
     * 在每个测试方法执行之前执行,获取SQLSession对象
     */
    @Before
    public void before() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        session = sqlSessionFactory.openSession();
    }
    
    /**
     * 测试SQL方法
     */
    @Test
    public void testInsertTeacher(){
    	//获取代理对象
        TeacherMapper mapper = session.getMapper(TeacherMapper.class);
        Teacher teacher = new Teacher();
        teacher.setTName("王五");
        //通过代理对象调用方法
        int row = mapper.insertTeacher(teacher);
        System.out.println(row);
    }

	/**
     * 在每个测试方法执行完后执行
     */
    @After
    public void after(){
	//     提交
        session.commit();
//        清空
        session.close();
    }
   
    }

四、Maven配置

在pom.xml文件中:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>mybatis</groupId>
    <artifactId>mybatis-study</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--相关依赖-->
    <dependencies>
        <dependency>
            <!--通用工具包-->
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.4</version>
        </dependency>
        <!--lombok依赖作用:不需要生成set和get方法-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>
		<!--mybatis依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <!--mysql依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--日志依赖-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
		<!--测试依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

五、mybatis核心配置文件

mybatis核心配置文件一般约定名为:mybatis-config.xml

<?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="logImpl" value="STDOUT_LOGGING"/>-->
        <!--使用log4j打印日志-->
        <setting name="logImpl" value="LOG4J"/>
        <!--开启驼峰命名自动映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    
    <!--给包entity下所有的实体类定义一个别名:默认为类名,不区分大小写-->
    <typeAliases>
        <package name="com.crc.entity" />
    </typeAliases>
    
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--数据源-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm?
                    useSSL=false;useUnicode=true&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--将接口类的配置文件注射给核心配置文件,这样才能达到对映的联系-->
    <mappers>
        <mapper resource="mappers/UserMapper.xml" />
        <mapper class="com.crc.dao.AdminMapper" />
        <mapper resource="mappers/DeptMapper.xml" />
        <mapper resource="mappers/EmployeeMapper.xml" />
        <mapper resource="mappers/TeacherMapper.xml" />
        <mapper resource="mappers/StudentMapper.xml" />
    </mappers>
</configuration>

六、mybatis的主要组成部分:

1、实体类:一般写在entity包中,对应数据库(一表一实体类),如:user表(User)。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private int id;
    private String username;
    private String password;
}

2、持久层:一般写在dao包中,对应实体类。通常使用Mapper结尾的接口。如:UserMapper

public interface UserMapper {
    //SQL方法,与resource中的对应的配置文件相互对应
    List<User> selectUsers();
}

3、配置文件:一般写在resource资源文件中。通常与持久层中的接口名一致。如:UserMapper.xml

<?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.crc.dao.UserMapper">

<!--接口中的方法名,类型名-->
    <select id="selectUsers" resultType="com.crc.entity.User">
    <!-- 执行的sql语句-->
        select id,username,password from user
    </select>
</mapper>

4、测试类:通过获取代理对象调用接口中的方法。(具体实现请看上面的代理模式代码)

总结:
mybatis实现SQL语句过程主要由这几个部分组成:接口类UserMapper编写SQL实现方法(方便java代码调用),配置文件UserMapper.xml 实现具体的接口方法(编写SQL语句)。

重要!!!一定要在mybatis-config.xml核心配置文件中配置对应的XXXMapper.xml 文件

<!--将接口类的配置文件注射给核心配置文件,这样才能达到对映的联系-->
    <mappers>
    	<!--通过配置文件-->	
        <mapper resource="mappers/UserMapper.xml" />
        <!--通过类-->	
        <mapper class="com.crc.dao.AdminMapper" />
    </mappers>

以上是最常用的配置方式。

方法二:
mybatis最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的。而到MyBatis 3提供了新的基于注解的配置。不幸的是,Java 注解的的表达力和灵活性十分有限。最强大的 MyBatis 映射并不能用注解来构建
sql 类型主要分成 :
@select ()
@update ()
@Insert ()
@delete ()
注意:利用注解开发就不需要mapper.xml映射文件了 .

七、动态SQL

1、简单介绍 < select > < insert > 等标签中节点的作用:

<!--
id:对应接口类中的方法名,也是两个文件之间相互映射的关键
resultType:方法的返回值类型,参数为类的全类名或者别名
parameterType:方法的参数类型,参数为类的全类名或者别名
-->
<select id="selectUserById" resultType="com.crc.entity.User" parameterType="int">
        select id,username,password from user where id = #{id}
    </select>

2、动态SQL中的元素:

元素作用备注
if判断语句单条件分支判断
choose、when、otherwise相当于Java中的 case when语句多条件分支判断
trim、where、set辅助元素用于处理一些SQL拼装问题
foreach循环语句在in语句等列举条件常用

if元素(最常用)

<select id="findUserById" resultType="com.xinzhi.entity.User">
select id,username,password from user
where 1 =1
<if test="id != null and id != ''">
AND id = #{id}
</if>
</select>

where元素
上面的select语句我们加了一个 1=1 的绝对true的语句,目的是为了防止语句错误,变成 SELECT * FROM
student WHERE 这样where后没有内容的错误语句。这样会有点奇怪,此时可以使用 元素

<select id="findUserById" resultType="com.xinzhi.entity.User">
	select id,username,password from user
	<where>
		<if test="id != null and id != ''">
			AND id = #{id}
		</if>
	</where>
</select>

choose、when、otherwise元素
有些时候我们还需要多种条件的选择,在Java中我们可以使用switch、case、default语句,而在映射器的动态语句中可以使用choose、when、otherwise元素。

<!-- 有name的时候使用name搜索,没有的时候使用id搜索 -->
<select id="select" resultType="com.xinzhi.entity.User">
	SELECT * FROM user
	WHERE 1=1
	<choose>
		<when test="name != null and name != ''">
		AND username LIKE concat('%', #{username}, '%')
		</when>
		<when test="id != null">
		AND id = #{id}
		</when>
	</choose>
</select>

trim元素
有时候我们要去掉一些特殊的SQL语法,比如常见的and、or,此时可以使用trim元素。trim元素意味着我们需要去掉一些特殊的字符串,prefix代表的是语句的前缀,而prefixOverrides代表的是你需要去掉的那种字符串,suffix表示语句的后缀,suffixOverrides代表去掉的后缀字符串。

<select id="select" resultType="com.xinzhi.entity.User">
	SELECT * FROM user
	<trim prefix="WHERE" prefixOverrides="AND">
		<if test="username != null and username != ''">
			AND username LIKE concat('%', #{username}, '%')
		</if>
		<if test="id != null">
			AND id = #{id}
		</if>
	</trim>
</select>

set元素
在update语句中,如果我们只想更新某几个字段的值,这个时候可以使用set元素配合if元素来完成。注意:set元素遇到,会自动把,去掉。

<update id="update">
	UPDATE user
	<set>
		<if test="username != null and username != ''">
			username = #{username},
		</if>
		<if test="password != null and password != ''">
			password = #{password}
		</if>
	</set>
	WHERE id = #{id}
</update>

foreach元素
foreach元素是一个循环语句,它的作用是遍历集合,可以支持数组、List、Set接口。

<select id="select" resultType="com.xinzhi.entity.User">
	SELECT * FROM user
	WHERE id IN
	<foreach collection="ids" open="(" close=")" separator="," item="id">
		#{id}
	</foreach>
</select>

SQL片段
有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

<!--提取SQL片段-->
<sql id ="select" > select * from </sql>

<!--引用SQL片段-->
<select id="queryBlogIf" parameterType="map" resultType="blog">
<include refid = "select"> 
</select>

八、#{} 与 ${} 的区别

相同点:

  • #{}:可以获取map中的值或者pojo对象属性的值;
  • ${}:可以获取map中的值或者pojo对象属性的值;

区别:

  • #{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
  • ${}:取出的值直接拼装在sql语句中;会有安全问题;

注意:大多情况下,我们去参数的值都应该去使用#{};

九、resultMap

属性名和字段名不一致,我们一般都会按照约定去设计数据的,但确实阻止不了一些孩子,瞎比起名字。
使用结果集映射->resultMap 【推荐】

<resultMap id="UserMap" type="User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="username" property="name"/>
<result column="password" property="password"/>
</resultMap>
<select id="selectUserById" resultMap="UserMap">
select id , username , password from user where id = #{id}
</select>

多表维护:

association 元素:

<resultMap id="select-employee-map" type="com.crc.entity.Employee">
        <!--
         association:复杂对象,用于一对一关系(一个员工对应一个部门)
         property:在实体类的属性名
         column:在表中对应的列名
         javaType:属性的类型
         select:将要执行的SQL
         根据查询SQL获得的 d_id 的值进行查询select节点
         过程理解:通过查询员工表employee 获得字段信息(如:d_id = 2)
         继续通过字段信息查询下一条SQL语句,将查到的结果存入实体类中
         最后通过字符串拼接
         -->
        <association property="dept" column="d_id" javaType="com.crc.entity.Dept"
                     select="com.crc.dao.DeptMapper.getDept" />

    </resultMap>

collection 元素:

<resultMap id="select-teacher-map" type="com.crc.entity.Teacher" >
        <collection property="student"
                    javaType="ArrayList" ofType="com.crc.entity.Student"
                    column="t_id" select="com.crc.dao.StudentMapper.getStuden" />
    </resultMap>

十、一些重要的配置

1、驼峰命名法
在数据库中我们通常习惯对表列名使用下划线名字(u_name),而在实体类中我们习惯使用驼峰命名法(uName)。因此会导致数据库列名与实体类属性名不一致的问题,解决方法:在mybatis-config.xml 核心文件中配置如下:

<settings>
   <!--开启驼峰命名自动映射-->
   <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

2、给自己的类起别名
在xxxMapper.xml 配置文件中,有时方法的返回值类型和参数类型可能使用我们自己定义的类,而每次都使用全类名可能有些复杂,因此可以对类定义别名从而替代全类名
在核心配置文件中加入

<typeAliases>	
	<!-- 指定单个类起别名-->
	<typeAlias type="com.xinzhi.entity.User" alias="user"/>
	<!-- 指定某个包内所有类起别名-->
	<package name="com.crc.entity"/>
</typeAliases>

< typeAlias > 标签中 有 type 和 alias 两个属性
type 填写 实体类的全类名, alias 可以不填,不填的话,默认是类名,不区分大小写,
alias 填了的话就以 alias里的值为准。

3、日志配置
标准日志实现
指定 MyBatis 应该使用哪个日志记录实现。如果此设置不存在,则会自动发现日志记录实现。
STD:standard out:输出
STDOUT_LOGGING:标准输出日志

<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

组合log4j完成日志功能(扩展)
使用步骤:
1、导入log4j的包

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

2、配置文件编写 log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

3、setting设置日志实现

<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>

十一、Mybatis缓存

1、为什么要用缓存?
如果缓存中有数据,就不用从数据库获取,大大提高系统性能。
mybatis提供一级缓存和二级缓存
2、一级缓存:(默认开启)
一级缓存是sqlsession级别的缓存

  • 在操作数据库时,需要构造sqlsession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据
  • 不同的sqlsession之间的缓存区域是互相不影响的。

3、二级缓存:(需要手动开启)
二级缓存是mapper级别的缓存

  • 多个sqlsession去操作同一个mapper的sql语句,多个sqlsession可以共用二级缓存,所得到的数据会存在二级缓存区域。
  • 二级缓存是跨sqlsession的
  • 二级缓存相比一级缓存的范围更大(按namespace来划分),多个sqlsession可以共享一个二级缓存

4、三级缓存
三级缓存是指第三方缓存。
在企业中通常使用第三方缓存。
坑点:
1、注释问题:在配置动态SQL的时候使用idea快捷键注释单行SQL代码时,idea会自动注释成
“-- SQL语句”
虽然显示和正常注释“<!- -->”代码一样效果,但是运行时会报错“Error updating database. Cause: org.apache.ibatis.type.TypeException: Could not set parameters for mapping…”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值