Mybatis 从 0 到 1(基础进阶教程)

给梦想一点时间,让它一步步成长 有事做、有人爱、有所期待 本文由博客端 https://www.wslhome.top 主动推送

又是实训 SSM,有关 MyBatis 有些东西还是不是那么熟悉,今天就来进阶一下吧 😂 :

引入依赖

在使用 MyBatis 肯定是需要引入依赖的

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>

一、mybatis-config.xml

mybatis-config.xml

1.首先引入固定的标签

<?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">

2.引入根标签(接下来的所有内容都在根标签中写)

<configuration>
... ...
</configuration>

3.配置使用 LOG4J 输出日志(非必须):

引入依赖:

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

在 resource 文件夹下添加 lo4j.properties 文件,内容如下

log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

在 XML 中添加 setting 设置

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

4.自定义控制台输出(非必须):

<appender name="console" class="">
      <encoder>
         <pattern>[%thread] %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
      </encoder>
</appender>
    <root level="debug">
    	<appender-ref ref="console"/>
    </root>

5.别名定义:

<typeAlias type="" alias="">当个别名定义

<package name="">批量别名定义,包下所有类名作为别名,大小写不敏感

<typeAliases>
        <typeAlias type="com.wsl.entity.User" alias="user"/>
	<package name="com.cai.mybatis.pojo" />
</typeAliases>

6.配置 db.properties (db.yml)数据源(可直接在 XML 中配置):

<properties resource="db.yml"></preperties>

7.配置开发环境:

<environments default="dev">
	<environment id="dev">
		<transactionManager type="JDBC"></transactionManager>
		<dataSource type="POOLED">
			<property/>
		</dataSource>
	</environment>
		<environment id="test"></environment>
			...  ...
<environments>

<environment id="test"></enviroment>设置开发环境 id 唯一标识

<transactionManager type = "JDBC"></transactionManager>开启 MyBatis 自带事务管理

<dataSource type = "POOLED">

<property name = "dirver|url|username|password" value=""/> 配置数据库

</dataSource>

8.配置 mapping.xml 文件映射

<mappers>
	<mapper resource="mapper/TestUserMapper.xml"/>
	<mapper class="com.wsl.mapper.UserMapper"/>
	<package name=""/>
</mappers>

<mapper resource = "">使用相对类路径的资源

<mapper class=""> 使用相对包路径资源

<package name = ""> 注册指定包下的所有 mapper 接口

end:汇总起来大致如下:

<?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>
	<properties resource="jdbc.yml"></properties>
	<settings>
		<setting name="logImpl" value="LOG4J"/>
	</settings>
	<typeAliases>
		<typeAlias type="com.wsl.entity.User" alias="user"/>
		<package name="com.cai.mybatis.pojo" />
	</typeAliases>

	<environments default="dev">
		<environment id="dev">
			<transactionManager type="JDBC"></transactionManager>
			<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>
		<environment id="rel">
			<transactionManager type="JDBC"></transactionManager>
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver"/>
				<property name="url" value=""/>
				<property name="username" value="root"/>
				<property name="password" value=""/>
			</dataSource>
		</environment>
	</environments>

	<mappers>
		<mapper resource="mapper/TestUserMapper.xml"/>
		<mapper class="com.wsl.mapper.UserMapper"/>
		<package name=""/>
	</mappers>

</configuration>

二、使用方式

XML 形式

只使用 XML 文件会造成很大的不便,采用 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">
<!-- 针对于数据库的sql语句(增删改查)操作,并且将sql语句的返回结果保存到相应类型中 -->
<!-- namespace是所有mapper.xml文件中的唯一标识,通常使用包名+类名 -->
<mapper namespace="com.wsl.entity.User">
	<!-- id表示在当前xml文件中的唯一标识 -->
	<insert id="insertUser">
		insert into user values(null,'test','321')
	</insert>
	<select id="selectUsers" resultType="com.wsl.entity.User">
		select  * from user
	</select>
	<update id="">... ...</update>
	<delete id="">... ...</delete>
</mapper>

@Test 测试:

@Test
public void testInsert() {
	InputStream in = Test.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
	//根据读取的配置文件创建工厂对象

	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
	//根据工厂对象获取sqlsession对象
	SqlSession sqlSession = sqlSessionFactory.openSession();
	//需要通过sqlSession对象来直接执行mapper.xml标签中的sql语句
	//参数为namespace+id,返回值表示本次插入影响的数据库行数
	int i = sqlSession.insert("com.wsl.entity.User.insertUser");
	//增删改都会影响数据库中的数据,最后都要手动提交
	sqlSession.commit();
	//将期望值和真实值做对比
	assertEquals(1, i);
}

接口 + 注解

使用@Update、@Insert、@select、@delect 相关的注解 + 接口实现 CUID

ps:在传参数时候,一个参数不用加@Parm 注解,如果是多个参数需要加入@Parm 注解

package com.wsl.mapper;

import com.wsl.entity.User;
import org.apache.ibatis.annotations.*;
import java.util.List;

public interface UserMapper {
  
    @Update("update user set name = #{name} where id = #{id}")
    int updataUser(@Param("name") String name,@Param("id") int id);

    @Insert("insert into user value (null,#{name},#{password})")
    int insertUser(@Param("name") String name, @Param("password") String password);

    @Select("select * from user")
    public List<User> selectuser();

    @Delete("delete from user where id = #{id}")
    public User delectById(Integer id);

}

@Test 测试

public class MybatisInterface {
    SqlSession sqlSession = getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  
    SqlSession getSqlSession(){
        //读取mybatis-config配置文件,把配置文件转化为流
        InputStream in = Test.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        //根据读取的配置文件创建工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = sqlSessionFactory.openSession();
        return session;
    }

    @Test
    public void testInsert() {

        int num = userMapper.insertUser("123","123");
        sqlSession.commit();
        System.out.println(num);

    }
}

接口 +xml

结合了 XML 与接口的特点,传参、解耦得到改善

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">
<!-- 针对于数据库的sql语句(增删改查)操作,并且将sql语句的返回结果保存到相应类型中 -->
<!-- namespace是所有mapper.xml文件中的唯一标识,通常使用包名+类名 -->

<mapper namespace="com.wsl.mapper.TestUsermapper">
	<!--对key重新名命-->
	<resultMap id="testMap" type="com.wsl.entity.User">
		<id column="id" property="id" />
		<result column="username" property="name" />
	</resultMap>
	<!-- id表示在当前xml文件中的唯一标识 -->
	<insert id="insertUser" parameterType="int">
	<selectKey resultType="java.lang.Integer" keyProperty="id" order="AFTER" >
	insert into user values(null,'test','321')
	</insert>
	<select id="selectAllUsers" resultType="com.wsl.entity.User">
		select  * from user
	</select>

	<delete id=""></delete>
	<update id=""></update>
	<select id="selectUser" resultType="com.wsl.entity.User">
		select  * from user where id = #{id}
	</select>

</mapper>

mapper.java 文件

public interface TestUsermapper {
    //添加学生
    int insertUser();
    //查询学生
    List<User> selectAllUsers();
    //查询学生
    User selectUser(Integer id);

}

@Test 文件

public class TestUserMapper {
    SqlSession sqlSession = getSqlSession();
    TestUsermapper testUserMapper = sqlSession.getMapper( TestUsermapper.class);

    SqlSession getSqlSession(){
        //读取mybatis-config配置文件,把配置文件转化为流
        InputStream in = Test.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        //根据读取的配置文件创建工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = sqlSessionFactory.openSession();
        return session;
    }

    @Test
    public void TestSelectAll(){
        List<User> users  = testUserMapper.selectAllUsers();
        sqlSession.commit();
        for (User user:users) System.out.println(user);
    }
}

属性说明:

(随便写几个,找了几个,剩下的可能在下面会用到)

$ 与 # 的区别

默认情况下,使用 #{}格式的语法会导致 MyBatis 创建预处理语句属性并安全地设置值(比如?)。这样做更安全,更迅速,通常也是首选做法,不过有时你只是想直接在 SQL 语句中插入一个不改变的字符串。当使用 ${} MyBatis 不会修改或转义字符串。以这种方式接受从用户输出的内容并提供给语句中不变的字符串是不安全的,会导致潜在的 SQL 注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验。

简单点说就是:# 会进行一个预编译检验,但是 $ 是直接赋值,不安全存在 SQL 注入

三、动态 SQL

if

<if test="">test 后为选择条件为真执行

<select id="selectAllUsers" resultType="com.wsl.entity.User">
	select  * from user
	<if test="id != null"> id = #{id}</if>
</select>

foreach

遍历传入的数组、list、map。

XML:

<select id="selectUser" resultType="com.wsl.entity.User">
	select  * from user where name in 
	<foreach collection="name" open="(" close=")" index="index" item="item" separator=",">
		#{item}
	</foreach>
</select>

interface:

List<User> selectUser(@Param("name") String[] name);

Test:

public class TestUserMapper {
    SqlSession sqlSession = getSqlSession();
    TestUsermapper testUserMapper = sqlSession.getMapper( TestUsermapper.class);

    SqlSession getSqlSession(){
        //读取mybatis-config配置文件,把配置文件转化为流
        InputStream in = Test.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        //根据读取的配置文件创建工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
        SqlSession session = sqlSessionFactory.openSession();
        return session;
    }
@Test
    public void TestSelect(){
        String[] array = {"wsl","test"};
        List<User> user  = testUserMapper.selectUser(array);
        sqlSession.commit();
        System.out.println(user);
    }
}

参数说明:

choose-when

当我们在传入值得时候进行选择判断,类似 Java 中 switch...case...default...。如果其中一个 when 标签满足则执行所在 <when>标签的 SQL 如果都不满足则执行 <otherwise>中的内容。

这里需要与 <if>标签做区别,<if>中的依次判断,如果满足就不断拼接,但是 <choose>标签中只会选择一个 <when>,如果遇到满足(为 ture)的时候,就再执行下面的标签。

<select id="selectUser" resultType="com.wsl.entity.User">
	select  * from user where
	<choose>
		<when test="name != null and name !=''">name = #{name}</when>
		<when test="id != null ">id = #{id}</when>
		<otherwise>1=1</otherwise>
	</choose>
</select>

where

自动添加 where 关键字、剔除 and、or 关键字

<select>SELECT * from user where
        <if test="name!=null and name!='' ">
            name =#{name}
	</if>
        <if test="password!= null and password!= '' ">
            AND password = #{password}
        </if>
</select>

上面例子中,如果第一个 if 不满足,但是第二个 if 满足的时候就会出现 ...where and ...错误 SQL 的情况。为了避免这种情况采用 <where>标签自动判断是否添加 where 关键字,并且自动剔除 and、or 关键字。

<select id="selectAllUsers" resultType="com.wsl.entity.User">
	select  * from user
	<where>
		<if test="password != null and password != '' != null"> password = #{password}</if>
		<if test="name != null and name !=''">and name = #{name}</if>
	</where>
</select>

set

当我们在执行 update 语句修改多字段的时候,最后一个 if 不执行将会导致 SQL 出错(多了个,)

<select id="selectAllUsers" resultType="com.wsl.entity.User">
	update user set
	<if test="name != null and name !=''">name = #{name},</if>
	<if test="password != null and password != '' != null"> password = #{password}</if>
	where id = #{id}
</select>

当 passowrd 字段为 null 时候将会导致错误出现,为了避免这种情况,采用 <set>标签自动剔除末尾逗号。

<select id="selectAllUsers" resultType="com.wsl.entity.User">
	update user set
	<set>
	    <if test="name != null and name !=''">name = #{name},</if>
	    <if test="password != null and password != '' != null"> password = #{password}</if>
	</set>
	where id = #{id}
</select>

trim

格式化标签,主要用于拼接 SQL 语句(前后缀等)

trim 属性:

<select id="selectUser" resultType="com.wsl.entity.User">
	select  * from user where
	<trim prefixOverrides="and|or">
		<if test="name != null and name !=''"> and name = #{name}</if>
		<if test="id != null ">and id = #{id}</if>
	</trim>
</select>

sql-include

当多种类型的查询语句的查询字段或者查询条件相同时,可以将其定义为常量,方便调用。为求 <select>结构清晰也可将 SQL 语句分解。通过 <include>标签包含其中

<sql id="userInfo">
	select name,password from user
</sql>
<select id="selectAllUsers" resultType="com.wsl.entity.User">
	<include refid="userInfo"></include>
	where id = #{id}
</select>

bind

bind 做字符串拼接,方便后续使用。

xml:

<select id="selectUser" resultType="com.wsl.entity.User">
	<bind name="name" value="'%'+name+'%'"/>
	select  * from user where name like #{name}
</select>

interface:

List<User> selectUser( @Param("name") String name);#必须使用@Parm注解

四、关联关系映射

associationcollection

association:通常用来映射多对一、一对一的关系。eg:一个学生只能属于一个班

collection:通常用来映射一对多的关系。eg:一个班里有多个学生

案例

查询一个班的基本信息与在这个班的学生基本信息(association 用法类似,更容易理解,此处不举例子)

多表单独查询 xml:

<select id="testselect" resultMap="testMap" >
		select * from sc where classid= #{id}
	</select>
	<resultMap id="testMap" type="com.wsl.entity.sc">
		<id property="id" column="id"/>
		<result property="classid" column="classid"/>
		<result property="userid" column="userid"/>
		<collection property="users" ofType="com.wsl.entity.User" select="test" column="userid"/>
	</resultMap>
	<select id="test" resultType="com.wsl.entity.User">
		select * from user where id = #{id}
	</select>

多表连接查询 XML

<select id="testselect" resultMap="testMap" >
		select * from sc,student where where sc.userid=user.id and classid= #{id}
	</select>
	<resultMap id="testMap" type="com.wsl.entity.sc">
		<id property="id" column="id"/>
		<result property="classid" column="classid"/>
		<result property="userid" column="userid"/>
		<collection property="users" ofType="com.wsl.entity.User">
			<id property="id" column="id"/>
			<result property="name" column="name"/>
			<result property="password" column="password"/>
		</collection>
	</resultMap>

sc:

@Data
public class sc {
    Integer id;
    Integer userid;
    Integer classid;
    User[] users;
}

User:

@Data
public class User {
    private Integer id;
    private String name;
    private String password;
}

五、MyBatis 逆向工程:

MyBatis 官方提供了 Mapper 自动生成工具,可以通过配置 generator.xml 文件,根据数据库表自动生成 pojo 类和 mapper 映射文件,接口文件。

PS:

1. 逆向工程生成的代码只能做单表查询
2. 不能在生成的代码上进行扩展,因为如果数据库变更,需要重新使用逆向工程生成代码,原来编写的代码就被覆盖了。

逆向工程文件包:mybatisgeneratorcore1.3.2.zip

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>

<!--修改成自己本机中mysql驱动包jar包路径-->
<!--此插件需要连接到数据库,读取数据库中内容帮助开发者生成实体类,所以我们需要为其制定一个jdbc的jar。他通过此jar包读取数据库 -->
	<classPathEntry location="E:\mybatis-generator-core-1.3.2\lib\mysql-connector-5.1.8.jar" />
	<context id="sysGenerator" targetRuntime="MyBatis3">

	<!--去除注释-->
        <commentGenerator >  
           <property name="suppressDate" value="true"/>  
            <property name="suppressAllComments" value="true"/>  
        </commentGenerator>  

<!-- 数据源,指定我们要生成实体类的数据库路径,用户名密码 -->
		<jdbcConnection 
		driverClass="com.mysql.jdbc.Driver"
			connectionURL="jdbc:mysql://121.19.0.0:3306/mytest" 
			userId="root" password="">
		</jdbcConnection>

	<!--用于配置实体类的所在的包targetPackage是包名
	targetProject指定生成的java代码和包存放的路径
	-->
		<javaModelGenerator targetPackage="com.math.hpu.domain"
			targetProject="E:\mybatis-generator-core-1.3.2\mybatis">
			<property name="enableSubPackages" value="true" />
			<property name="trimStrings" value="true" />
		</javaModelGenerator>

		<!--xml文件存在包和路径-->
		<sqlMapGenerator targetPackage="com.math.hpu.domain"
			targetProject="E:\mybatis-generator-core-1.3.2\mybatis">
			<property name="enableSubPackages" value="true" />
		</sqlMapGenerator>

		<!--配置接口存在包和保存的路径targetPackage表示包名,targetProject生成的文件保存的位置-->
		<javaClientGenerator type="XMLMAPPER"
			targetPackage="com.math.hpu.mapper" targetProject="E:\mybatis-generator-core-1.3.2\mybatis">
			<property name="enableSubPackages" value="true" />
		</javaClientGenerator>

		<!--指定生成哪些表-->

		<!--每张表都需要对应一个table标签对他表示设置-->
		<!--tableName表示表名,domainObjectName 表示实体类的名字-->
		<table tableName="user" domainObjectName="User" 

			enableCountByExample="false"
			enableUpdateByExample="false" enableDeleteByExample="false"
			enableSelectByExample="false" selectByExampleQueryId="false">
			<generatedKey column="ID" sqlStatement="MYSQL" identity="true" />
		</table>

	</context>
</generatorConfiguration>

六、MyBatis 二级缓存

一级缓存:

一级缓存默认开启,缓存范围为 SqlSession 会话,即一个 session 对象,范围太小,声明周期短。两个 session 对象查询后,数据存储在不同的内存地址中。当我们在 commit 提交后会强制清空 namespace 缓存。高缓存命中率,提高查询速度,使用二级缓存。

二级缓存:

二级缓存的范围大,属于范围 Mapper Namespace,周期长。需要设置 catch 标签。在一个 namespace 空间内,多个 session 对象执行同一个 id 的查询,查询后的数据放在一个缓存地址中。第一次从硬盘的数据库中查询数据,后面再次查询不再执行 SQL 语句,直接从缓存中提取数据,速度更快。

<cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"/>

eviction:是缓存策略

flushInterval:是间隔时间,单位毫秒

size:是二级缓存大小(缓存上限)

readOnly:

使用规则:

<!-- 不建议把包含很多的list集合保存到缓存中,缓存命中率低 设置useCache="false"不使用缓存-->
<select id="selectAll" resultType="com.wsl.pojo.user" useCache="false">
    select * from user
</select>

七、pageHelper 使用

引入依赖:

<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper</artifactId>
	<version>5.1.2</version>
</dependency>

<!--开始引入2.0的jsqlparser会出现错误,不知道什么原因-->  
<dependency>	<groupId>com.github.jsqlparser</groupId>
   	 <artifactId>jsqlparser</artifactId>
  	  <version>1.4</version>
</dependency>

mybatis-config.xml 增加 Plugin 配置

<plugins>
    <!-- 配置拦截器插件,新版拦截器是 com.github.pagehelper.PageInterceptor-->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <!--设置数据库类型-->
        <property name="helperDialect" value="mysql"/>
        <!--分页合理化-->
        <property name="reasonable" value="true"/>
    </plugin>
</plugins>

service 层运用:

PageHelper.startPage(2,10);

测试:

@Test
    public void test(){
        PageHelper.startPage(1,5);
        List<User> users = testUserMapper.selectAllUsers();
        sqlSession.commit();
        for (User user:users)System.out.println(user);
    }
}

八、MyBatis 整合 c3p0 连接池

引入依赖:

<dependency>
    <groupId>com.mchange</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.5.4</version>
</dependency>

创建 C3P0 数据源:

public class C3P0Data extends UnpooledDataSourceFactory {
    public C3P0Data(){
        this.dataSource = new ComboPooledDataSource();
    }
}

修改 mybatis-config.xml 数据连接:

<dataSource type="com.wsl.datesource.C3P0Data">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mytest?useUnicode=true&characterEncoding=UTF-8&SSL=false"/>
    <property name="user" value="root"/>
    <property name="password" value=""/>
    <property name="initialPoolSize" value="5"/>
    <property name="maxPoolSize" value="20"/>
    <property name="minPoolSize" value="5"/>
</dataSource>

文章到此结束,写了一天,实在是写不动了。

  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 Google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    150 引用 • 404 回帖 • 691 关注
2 操作
sirwsl 在 2020-07-30 22:38:05 更新了该帖
sirwsl 在 2020-07-30 20:31:48 更新了该帖

赞助商 我要投放

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...