为了账号安全,请及时绑定邮箱和手机立即绑定

MyBatis Plus学习笔记(一)

标签:
Java SSM

image-20210203110644329

1.MyBatis 介绍

MyBatis是一种持久层框架,和Hibernate等一样是作为操作数据库底层的处理方案。持久层的作用可以把实体对象转换为SQL语句,或者使用自定义的SQL语句去操作数据库,然后把返回的数据再映射为实体对象返回给调用者。

在传统的 JDBC 中,我们除了需要自己提供 SQL 外,还必须操作 Connection、Statment、ResultSet,不仅如此,为了访问不同的表,不同字段的数据,我们需要些很多雷同模板化的代码,闲的繁琐又枯燥。
而使用了 MyBatis 之后,只需要提供 SQL 语句就好了,其余的诸如:建立连接、操作 Statment、ResultSet,处理 JDBC 相关异常等等都可以交给 MyBatis 去处理,我们的关注点于是可以就此集中在 SQL 语句上,关注在增删改查这些操作层面上。

1.1. SpringMVC下MyBatis的集成

1.1.1. Spring工程搭建

1.1.1.1. 创建Maven工程

创建一个 Maven工程,工程结构目录如下:

1.1.1.2. 配置pom文件

将需要的包引入到工程里面,以下是需要的jar包配置。

<dependencies>
    <!--junit测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!--日志相关-->
    <dependency>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
        <version>1.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>log4j-over-slf4j</artifactId>
        <version>1.7.21</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
        <scope>test</scope>
    </dependency>

    <!--mybatis的包-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.2.8</version>
    </dependency>
    <!--mybatis和spring整合相关的包-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.2.2</version>
    </dependency>
    <!--spring相关-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.1.3.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <exclusions>
            <!-- 排除掉 Commons Logging 相关的包 -->
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
        <version>4.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>4.1.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.1.3.RELEASE</version>
    </dependency>

    <!--MySQL驱动包-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.46</version>
    </dependency>
    <!--数据连接池相关包-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.12</version>
    </dependency>
</dependencies>

1.1.1.3. 增加相关的配置文件

如果是开发完整的web工程,需要编写相应的配置文件,我们只是为了简单的使用测试使用一下MyBatis相关的功能,所以只配置这一个相关的即可。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 引入配置文件 -->
    <context:property-placeholder location="classpath:config/db.properties"/>

    <!-- 配置数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="maxActive" value="10" />
        <property name="minIdle" value="5" />
        <property name="logAbandoned" value="true" />
    </bean>

    <!-- 配置sqlsessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"></property>
    </bean>

    <!-- 配置扫描包,加载mapper代理对象 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.zzlh.mp.mapper"></property>
    </bean>
    
    <!--如果不是用自动扫描,则需要为每一个mapper代理对象手动配置
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
     	<property name="mapperInterface" value="com.zzlh.mp.mapper.UserMapper" />
     	<property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    -->

</beans>

注:1、在配置sqlsessionFactory中关于configLocation是配置MyBatis自己相关的一些配置的,目前使用不到,可以不用配置。
2、配置扫描包路径必须和项目中真实路径保持一致

这里看到引入了一个数据库相关的配置文件,所以编写一个db.properties,编写数据库连接相关的内容

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mp?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root

还需要一个Mybatis自己相关的配置文件SqlMapConfig,,里面配置了日志和缓存相关的内容。

<?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="LOG4J"/>
        <!-- 二级缓存开启 -->
        <setting name="cacheEnabled" value="true"/>
        <setting name="lazyLoadingEnabled" value="false"/>
        <setting name="aggressiveLazyLoading" value="true"/>
    </settings>
</configuration>

此时的工程目录结构如下:

image-20210112112903388

接下来编写实体和Mybatis的mapper代理,由于我们只是使用junit进行单元测试的方式进行mybatis的学习,就不编写controller相关的代码了。

1.1.1.4. 编写相关的Java代码

在src/java下面新建com.zzlh.mp.entity包,里面存放的是各种实体类对应数据库中的每一张表。我们以user表为例创建一个User.java文件。

public class User {
//对应数据库中的表字段
private Long id;
private String name;
private Integer age;
private String email;

public User() {
}
//方便创建测试用例重写了实例化方法
public User(Long id, String name, Integer age, String email) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.email = email;
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Integer getAge() {
    return age;
}

public void setAge(Integer age) {
    this.age = age;
}

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

//方便打印输出,重写了toString方法
@Override
public String toString() {
    return "User{" +
            "id=" + id +
            ", name='" + name + '\'' +
            ", age=" + age +
            ", email='" + email + '\'' +
            '}';
}

在src/java下面新建com.zzlh.mp.mapper包,里面存放的是MyBatis的代理接口和对应的xml文件。
首先UserMapper.java,是一个接口类,里面定义了各种接口方法。

package com.zzlh.mp.mapper;

import com.zzlh.mp.entity.User;

import java.util.List;
import java.util.Map;

public interface UserMapper {

    int insertUser(User user);

    int deleteUserById(int userId);

    int updateUser(User user);

    User getUserById(int userId);

    User selectOne(User user);

    List<User> listUserByMap(Map<String,Object> paramMap);

    List<User> listUser(User user);

    List<User> selectAll();
}

然后是UserMapper.xml,里面是根据Mybatis语法规则编写的sql语句。

<?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.zzlh.mp.mapper.UserMapper">
    <resultMap id="UserMap" type="com.zzlh.mp.entity.User">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="age" column="age" />
        <result property="email" column="email" />
    </resultMap>

    <insert id="insertUser" parameterType="com.zzlh.mp.entity.User">
        insert into user (id,name,age,email) value (#{id,jdbcType=DECIMAL},#{name,jdbcType=VARCHAR},#{age,jdbcType=DECIMAL},#{email,jdbcType=VARCHAR})
    </insert>

    <delete id="deleteUserById" parameterType="int">
        delete from user where id = #{userId,jdbcType=DECIMAL}
    </delete>

    <update id="updateUser" parameterType="com.zzlh.mp.entity.User">
        update user set name=#{name,jdbcType=VARCHAR},age=#{age,jdbcType=DECIMAL},email=#{email,jdbcType=VARCHAR} where id=#{id,jdbcType=DECIMAL}
    </update>

    <select id="getUserById" parameterType="int" resultType="com.zzlh.mp.entity.User">
        select * from user where id=#{userId,jdbcType=DECIMAL}
    </select>

    <select id="selectOne" parameterType="com.zzlh.mp.entity.User" resultType="com.zzlh.mp.entity.User">
        select * from user where id=#{userId,jdbcType=DECIMAL}and name=#{name,jdbcType=VARCHAR} and age=#{age,jdbcType=DECIMAL} and email=#{email,jdbcType=VARCHAR}
    </select>

    <select id="listUserByMap" parameterType="hashmap" resultType="com.zzlh.mp.entity.User">
        select * from user where id=#{userId,jdbcType=DECIMAL}and name=#{name,jdbcType=VARCHAR} and age=#{age,jdbcType=DECIMAL} and email=#{email,jdbcType=VARCHAR}
    </select>

    <select id="listUser" parameterType="com.zzlh.mp.entity.User" resultType="com.zzlh.mp.entity.User">
        select * from user where id=#{userId,jdbcType=DECIMAL}and name=#{name,jdbcType=VARCHAR} and age=#{age,jdbcType=DECIMAL} and email=#{email,jdbcType=VARCHAR}
    </select>

    <select id="selectAll" resultType="com.zzlh.mp.entity.User">
        select * from user
    </select>

</mapper>

我们可以看到xml文件中每一个标签通过id和java文件的接口方法一一对应。里面就是我们写的SQL语句,然后参数通过MyBatis的表达式来进行标识。这时候的工程目录结构如下:

image-20210113164503815

1.1.1.5. 编写测试类

在test/java下面创建com.zzlh.mp包,在里面首先添加一个JUnit4ClassRunner.java,这个类用来加载log4j.properties文件。

public class JUnit4ClassRunner extends SpringJUnit4ClassRunner {
    static {
        try {
            Log4jConfigurer.initLogging("config/log4j.properties");
        } catch (FileNotFoundException ex) {
            System.err.println("Cannot Initialize log4j");
        }
    }
    public JUnit4ClassRunner(Class<?> clazz) throws InitializationError {
        super(clazz);
    }
}

然后编写一个测试类,SampleTest.java来测试功能。

@RunWith(JUnit4ClassRunner.class)//自定义加载过log4j配置文件的类
@ContextConfiguration(locations = {"classpath*:spring.xml"})
public class SampleTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        List<User> userList = userMapper.selectAll();
        userList.forEach(System.out::println);
    }

}

工程目录如下:

image-20210113164552934
运行测试方法testSelect(),在控制台输出的日志可以看到以下异常:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.zzlh.mp.mapper.UserMapper.selectAll

	at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:189)
	at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:43)
	at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:58)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:51)
	at com.sun.proxy.$Proxy14.selectAll(Unknown Source)
	at com.zzlh.mp.SampleTest.testSelect(SampleTest.java:33)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:217)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

这是编译的时候,src/java下面的*maaper.xml的文件没有被编译,所以我们需要在pom文件里面配置将它编译。

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

再次运行测试类,查看日志,执行成功,打印出来sql语句和输出结果。

com.zzlh.mp.mapper.UserMapper.selectAll - ==>  Preparing: select * from user 
com.zzlh.mp.mapper.UserMapper.selectAll - ==> Parameters: 
com.zzlh.mp.mapper.UserMapper.selectAll - <==      Total: 7
org.mybatis.spring.SqlSessionUtils - Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2692b61e]
org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
User{id=1, name='Jone', age=18, email='test1@baomidou.com'}
User{id=2, name='Jack', age=20, email='test2@baomidou.com'}
User{id=3, name='Tom', age=28, email='test3@baomidou.com'}
User{id=4, name='Sandy', age=21, email='test4@baomidou.com'}
User{id=5, name='Billie', age=24, email='test5@baomidou.com'}
User{id=6, name='张三', age=34, email='22@qq.com'}
User{id=7, name='李四', age=33, email='ls@qq.com'}

注:1、控制台输出的sql语句是没有经过整合的,就是语句和参数是分离的,如果需要排查问题,需要自己整合sql语句,如果参数过多可能比较麻烦,针对IDEA有MyBatis的插件MyBatis Log Plugin可以将sql自动整合。

image-20210113164632632
2、mapper.java和mapper.xml放在一起不用配置,但是一般把配置类的文件放在java目录里面比较不推荐,一般是将xml文件放在resources里面然后通过spring配置文件指定即可。所以我们可以改为。
首先将pom的build配置取消,然后在spring.xml文件里面sqlSessionFactory配置上mapper.xml的路径。

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"></property>
    <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"></property>
    <!--增加mapper.xml的路径 -->
    <property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>

此时目录结构如下:

image-20210113164717160
再次运行测试类,运行成功。

image-20210113164736536

1.1.1.6. 小结

1、MyBatis这种持久化技术和jdbc、hibernate对比的特点是

  • 首先是sql和java代码分离,好处是让sql分离维护,临时修改不需要重新编译。
  • 支持定制化 SQL、存储过程以及高级映射。
  • 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

2、MyBatis的缺点

  • mapper.xml里面的sql片段不容易维护。当一个mapper里面的方法越来越多,sql片段就会越凌乱,不方便查找,在IDEA之前的Eclipse等编辑器里面要想找到一个对应的sql片段效率是很低的。
    举个例子 cust-mapper.xml
  • 可定制化的有点是灵活,缺点就是不容易维护和二次开发,比如数据库字段更新了,要重新生成po和sql代码片段,如果是我们对po文件增加过属性,那么重新生成的po文件就不能直接使用要么用对比工具排查,要么使用包装类继承原生po。不管怎么处理都不方便维护和管理。
  • 每一个对应的mapper都要写大量的基础增删改查的方法和语句。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消