MyBatis

Mybatis

自定义插件

Mybatis怎么自定义实现插件?

自定义mybatis插件的本质就是使用拦截器去干预mybatis的执行:我们可以通过一个Interceptor拦截接口去管理mybatis的四个对象

  1. Executor:它负责调用 StatementHandler 操作数据库,并把结果集通过 ResultSetHandler 进行自动映射,另外它还处理了二级缓存的操作

    • 基本功能:改、查,没有增删的原因是所有的增删操作都可以归结到改。

    • 缓存维护:这里的缓存主要是为一级缓存服务,功能包括创建缓存Key、清理缓存、判断缓存是否存在。

    • 事务管理:提交、回滚、关闭、批处理刷新。(一般我们都交由spring管理,不会使用mybatis的)

  2. StatementHandler:拦截 SQL 语法构建的处理,用于执行SQL语句,另外它也实现了 MyBatis 的一级缓存;

  3. ParameterHandler:拦截参数的处理。

  4. ResultSetHandler:拦截结果集的处理。

数据脱敏插件

数据脱敏,是对数据进行处理,因此我们只需要通过拦截器Interceptor对ResultSetHandler进行拦截处理即可

定义一个枚举类

/**
 * 继承JDK8提供的一个函数式接口
 * 该接口的apply方法返回值是Function第二个参数,参数是该Function的第一参数
 */
public interface DesensitizationFunction extends Function<String,String> {

}

定义一个枚举类来设置各种脱敏方式

/**
 * 制定脱敏的方式
 * 考虑到对不同的属性进行脱敏,我们可以使用枚举类
 */
public enum DesensitizationWay {
	//通过正则表达式规定脱敏策略
    USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)","$1*$2")),
    ID_CARD(s -> s.replaceAll("(?<=\\w{3})\\w(?=\\w{4})", "*")),
    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
    ADDRESS(s -> s.replaceAll("(\\S)\\S*(\\S)","$1****$2")),
    ;
    private final DesensitizationFunction desensitizationFunction;

    DesensitizationWay(DesensitizationFunction desensitizationFunction) {
        this.desensitizationFunction = desensitizationFunction;
    }

    public DesensitizationFunction getDesensitizationFunction() {
        return desensitizationFunction;
    }
}

自定义一个注解

将这个定义的注解用到实体类上,设定字段脱敏的规则

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD) //作用在属性上
@Retention(RetentionPolicy.RUNTIME) //运行的时候生效
public @interface Desensitization {
    //脱敏的方式
    DesensitizationWay way();
}

定义拦截器

  1. 继承Interceptor拦截器

  2. 通过@Intercepts注解指定要拦截哪个类那个方法,args中的值是拦截方法的参数

  3. 通过@Component将拦截器注入的spring容器

  4. 重新intercept方法

import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import java.util.stream.Stream;

@Intercepts(@Signature(type = ResultSetHandler.class,method ="handleResultSets",args = Statement.class))
@Component
public class DesensitizationPlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //先获取到要脱敏的结果集
        List<Object> result=(List<Object>)invocation.proceed();
        //将结果集进行便利脱敏处理
        result.forEach(this::desensitization);
        //返回脱敏后的结果
        return result;
    }
    //脱敏
    private void desensitization(Object obj){
        //获取要脱敏对象的class
        Class<?> sourceClass=obj.getClass();
        //获取脱敏对象的结果集
        MetaObject metaObject= SystemMetaObject.forObject(obj);
        //看那些属性使用了Desensitization注解
        Stream.of(sourceClass.getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(Desensitization.class))
                .forEach(field -> tuoMin(metaObject,field) );

    }

    private void tuoMin(MetaObject metaObject, Field field) {
        String name=field.getName();
        Object value=metaObject.getValue(name);
        //字段属性必须是字符串,值不为空才能够进行脱敏
        if(String.class==metaObject.getGetterType(name) && value !=null){
            Desensitization desensitization=field.getAnnotation(Desensitization.class);
            DesensitizationWay type=desensitization.way();
            Object obj=type.getDesensitizationFunction().apply((String)value);
            metaObject.setValue(name,obj);
        }
    }
}

业务代码

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class DUser {
    private Integer id;
    @Desensitization(way = DesensitizationWay.PHONE)
    private String phone;
    @Desensitization(way = DesensitizationWay.ADDRESS)
    private String address;
    @Desensitization(way = DesensitizationWay.ID_CARD)
    private String card;
    @Desensitization(way = DesensitizationWay.USERNAME)
    private String username;
}

接口类:此处省略mapper.xml的编写,根据自己需要写即可

@Repository
@Mapper
public interface MyBatisMapper {
    //查询所有用户
    List<DUser> selectAllUser();
}

controller类

@RestController
@RequestMapping("/mybatis")
public class MybatisController{
    @Resource
    MyBatisMapper myBatisMapper;
    /**
     * 此接口返回的数据就是脱敏后的数据
     */
    @GetMapping("/tuoMin")
    public String tuoMin(){
        List<DUser> list=myBatisMapper.selectAllUser();
        return list.toString();
    }
}

sql打印插件

mybatis提供的sql语句打印功能,参数是?代替的,下面案例将展示打印完整的sql语句

定义拦截器

  • 要制作sql打印插件我们可以通过拦截Executor或者StatementHandler获取到sql语句对象

  • 下面我们通过拦截Executor的query方法和update方法来实现打印sql的功能

  • 推荐博客:MappedStatementinvocation.proceed()

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
@Component
public class SqlPlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //获取MappedStatement,MappedStatement可以理解为xml的一个查询/更新语句节点<select|update|delete|insert>
        MappedStatement mappedStatement=(MappedStatement) invocation.getArgs()[0];
        //获取sql语句的参数
        Object parameter=invocation.getArgs()[1];
        /*
         *获取Mybatis提供的BoundSql拿到sql语句
         * 第一个query中有BoundSql,可以直接通过invocation取出来,
         * 但第二个query和update没有BoundSql参数,我们还可以通过MappedStatement拿到boundSql
         */
        BoundSql boundSql=mappedStatement.getBoundSql(parameter);
        //拿到configuration对象
        Configuration configuration=mappedStatement.getConfiguration();
        //计算sql的执行时间
        long start = System.currentTimeMillis();
        Object result=null;
        try{
            /*
             *Object intercept(Invocation invocation)是实现拦截逻辑的地方,
             * 内部要通过invocation.proceed()显式地推进责任链前进,也就是调用下一个拦截器拦截目标方法。
             */
            result=invocation.proceed();
        }finally {
            long end=System.currentTimeMillis();
            System.out.println("执行时间为:"+(end-start)+"毫秒");
            //获取我们要执行的sql
            String sql=getSql(configuration,boundSql);
            System.out.println("执行sql为:"+sql);
        }
        return result;
    }

    private String getSql(Configuration configuration, BoundSql boundSql) {
        //如果sql为空的话
        String sql=boundSql.getSql();
        if(sql==null || sql.length()==0){
            return "没有可以执行的sql语句";
        }
        //格式化sql语句,我们自定义美化mybatis提供的sql打印格式
        sql=FormatSql(sql);
        /*
         * 将?替换成我们真正的参数
         * boundSql.getParameterMappings();可以拿到#{}中的值
         * TypeHandlerRegistry:获取参数类型的处理器【int/string/对象等等】
         */
        Object parameterObject=boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings=boundSql.getParameterMappings();
        if (!parameterMappings.isEmpty() && parameterObject!=null){
            TypeHandlerRegistry typeHandlerRegistry=configuration.getTypeHandlerRegistry();
            //如果参数是基本类型(不包含对象类型的参数)
            if(typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())){
                sql=replaceSql(sql,parameterObject);
            }else { //当参数复杂类型,对象等
               //MetaObject对象就是我们传入的对象参数
                MetaObject metaObject=configuration.newMetaObject(parameterObject);
                for(ParameterMapping parameterMapping:parameterMappings){
                    //拿到对象的属性名称
                    String propertyName=parameterMapping.getProperty();
                    if(metaObject.hasGetter(propertyName)){
                       Object obj=metaObject.getValue(propertyName);
                       sql=replaceSql(sql,obj);
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        /*
                         *还有一种情况就是在xml中写sql时,如果用到了foreach标签,
                         * 里面我们是通过#{对象.属性}的方式来获取参数的。
                         * 这种方式的参数是动态的,参数没有固定的名称
                         * boundSql.hasAdditionalParameter(propertyName用来判断是否有动态参数
                         */
                        Object obj=boundSql.getAdditionalParameter(propertyName);
                        sql=replaceSql(sql,obj);
                    }
                }
            }
        }
        return sql;
    }

    //对参数的不同类型做不同的处理
    private String replaceSql(String sql, Object parameterObject) {
        String result;
        //如果参数是字符串类型需要加上单引号
        if(parameterObject instanceof String){
            result ="'"+parameterObject.toString()+"'";
        }else if(parameterObject instanceof Date){
            //如果参数是时间类型
            result="'"+new SimpleDateFormat("yy-MM-dd HH:mm:ss").format(parameterObject.toString())+"'";
        }else {
            result=parameterObject.toString();
        }
        //将?替换为处理后的参数
        return sql.replaceFirst("\\?",result);
    }

    //如果我们想自定义sql的输出格式,我们就可以在下面方法进行自定义
    private String FormatSql(String sql) {
        //将换行或多个连续空格换为一个空格
        return sql.replaceAll("[\\s\n]+"," ");
    }
}

测试接口

    //查询所有用户
    List<DUser> selectAllUser();

    //根据id查询用户
    DUser selectById(Integer id);

    //根据提供的id集合查询数据
    List<DUser> selectByIds(@Param("userIds") List<Integer> userIds);

    //动态查询,sql中通过条件if进行判断
    List<DUser> selectByCondition(DUser user);

    //批量插入用户
    int insertUsers(@Param("users") List<DUser> users);
<!--    查询所有用户-->
    <select id="selectAllUser" resultType="DUser">
       select * from DUser;
    </select>
<!--    根据id查询用户-->
    <select id="selectById" resultType="DUser" parameterType="DUser">
        select * from DUser where id=#{id};
    </select>
<!--    根据集合中的所有id查询对应的用户-->
    <select id="selectByIds" resultType="DUser">
        select * from DUser where id in
        <foreach collection="userIds" item="userId" separator="," open="(" close=")">
            #{userId}
        </foreach>
    </select>
<!--    动态查询,sql中通过条件if进行判断-->
    <select id="selectByCondition" resultType="DUser" parameterType="DUser">
        select * from DUser
        <where>
            <if test='id !=null and id !=""'>
                id=#{id}
            </if>
            <if test='username !=null and username !=""'>
                and username=#{username}
            </if>
            <if test='phone !=null and phone !=""'>
                and phone=#{phone}
            </if>
        </where>
    </select>
<!--    批量插入用户-->
    <insert id="insertUsers">
        insert into DUser (phone,address,card,username) values
        <foreach collection="users" item="user" separator=",">
            (#{user.phone},#{user.address},#{user.card},#{user.username})
        </foreach>
    </insert>

调用接口和测试结果如下

@GetMapping("/printSql/{index}")
    public Object printSql(@PathVariable int index){
        switch (index){
            case 1:
                //查询所有用户
                return myBatisMapper.selectAllUser();
            case 2:
                //根据id查询用户
                return myBatisMapper.selectById(2);
            case 3:
                //根据id集合查询用户
                Integer[] list=new Integer[]{1, 2, 3, 4, 5};
                return myBatisMapper.selectByIds(Arrays.asList(list));
            case 4:
                //根据if判断查询数据
                DUser user=new DUser();
                user.setId(2);
                user.setUsername("韩非");
                return myBatisMapper.selectByCondition(user);
            case 5:
                List<DUser> users = new ArrayList<>();
                for (int i = 0; i < 4; i++) {
                    DUser user1=new DUser();
                    user1.setPhone("11111111111");
                    user1.setUsername("测试");
                    user1.setAddress("xxxxxxxxxxxxxxx");
                    user1.setCard("222222222222222222");
                    users.add(user1);
                }
                return myBatisMapper.insertUsers(users);
        }
        return "请输入1到5的数字";
    }
执行时间为:9毫秒
执行sql为:select * from DUser;
执行时间为:3毫秒
执行sql为:select * from DUser where id=2;
执行时间为:7毫秒
执行sql为:select * from DUser where id in ( 1 , 2 , 3 , 4 , 5 )
执行时间为:2毫秒
执行sql为:select * from DUser WHERE id=2 and username='韩非'
执行时间为:13毫秒
执行sql为:insert into DUser (phone,address,card,username) values ('11111111111','xxxxxxxxxxxxxxx','222222222222222222','测试') , ('11111111111','xxxxxxxxxxxxxxx','222222222222222222','测试') , ('11111111111','xxxxxxxxxxxxxxx','222222222222222222','测试') , ('11111111111','xxxxxxxxxxxxxxx','222222222222222222','测试')

mapper的编写方式

mapper编写有哪几种方式?

下面的案例也可以是看做在Spring中整合Mybatis的方式,总共有三种方式。

  1. 使用 MapperFactoryBean

  2. 接口实现类继承SqlSessionDaoSupport

  3. 使用Mapper扫描器MapperScannerConfigurer

案例环境准备

pom文件

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.1.10.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.2</version>
    </dependency>
    <!--mysql驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.17</version>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.4</version>
    </dependency>
    <!--junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!--lombok-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.20</version>
    </dependency>
</dependencies>
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    Integer id;
    String userName;
    Integer age;
    Integer sex;
    String createTime;
}

接口层

 UserMapper.java

public interface UserMapper {
    public List<User> selectUser();
}

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.dongjixue.dao.UserMapper">
    <select id="selectUser" resultType="com.dongjixue.pojo.User">
        select * from user
    </select>
</mapper>

 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>
    <!--实体类位置-->
    <typeAliases>
        <package name="com.dongjixue.pojo"/>
    </typeAliases>
    <mappers>
        <!-- 添加映射文件到Mybatis的全局配置文件中 -->
        <mapper resource="com/dongjixue/dao/UserMapper.xml" />
    </mappers>
</configuration>

 resource/spring-config.xml

使用不同方式来编写mapper,spring-config.xml的编写略有差异,详细见下。

测试

public class MyTest {
    @Test
    public void selectUser() {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        UserMapper userMapper=(UserMapper)context.getBean("userMapper");
        List<User> users=userMapper.selectUser();
        System.out.println(users);
    }
}

输出结果

[User(id=1, userName=张三, age=18, sex=1, createTime=2022-05-03), User(id=2, userName=红莲, age=16, sex=0, createTime=2022-05-14)]

SqlSessionDaoSupport方式

mapper第一种编写方式:接口实现类继承 SqlSessionDaoSupport

UserMapperImpl.java

使用SqlSessionDaoSupport方式必须写一个类实现UserMapper接口,其它方式不用写这个实现类

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> selectUser() {
        return getSqlSession().getMapper(UserMapper.class).selectUser();
    }
}

spring-config.xml

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--1.数据库连接池-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/learn_vue?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!-- spring 和 mybatis 整合 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定 mybatis 要连接的数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!--关联Mybatis-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!--注入mapper接口实现类-->
    <bean id="userMapper" class="com.dongjixue.dao.UserMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

MapperFactoryBean方式

mapper第二种编写方式:使用MapperFactoryBean映射器的方式

我们为啥要使用MapperFactoryBean

为了代替手工使用 SqlSessionDaoSupport 或 SqlSessionTemplate 编写数据访问对象(DAO)的代码,MyBatis-Spring 提供了一个动态代理的实现——MapperFactoryBean。这个类可以让你直接注入数据映射器接口到你的 service 层bean 中。当使用映射器时,你仅仅如调用你的 DAO 一样调用它们就可以了,但是你不需要编写任何 DAO 实现的代码,因为 MyBatis-Spring将会为你创建代理。

也就是说dao层的对数据访问对象被映射器直接注入到了service层,因此这个dao实现类就没必要写和注册了,从而简化操作,那么sqlsession也就不需要了吧。

spring-config.xml

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--数据库连接池-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/learn_vue?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!--配置SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--关联Mybatis-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!--注入dao层接口-->
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="com.dongjixue.dao.UserMapper"/>
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

目录结构

MapperScannerConfigurer方式

mapper第三种编写方式:MapperScannerConfigurer 自动扫描 将Mapper接口生成代理注入到Spring

MapperScannerConfigurer 和 MapperFactoryBean的比较

上面案例我们提到过MapperFactoryBean也能生成Mapper接口代理,但是却有一个缺点就是每一个接口都需要我们去注册一下。MapperScannerConfigurer 直接就能扫描到一个包下面的所有接口

<!--MapperFactoryBean:每一个接口都需要这样注册-->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.dongjixue.dao.UserMapper"/>
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

<!-- MapperScannerConfigurer :扫描的是一个包下的所有程序 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dongjixue.dao"/>
    </bean>

spring-config.xml

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--1.数据库连接池-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/learn_vue?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!-- spring 和 mybatis 整合 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定 mybatis 要连接的数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!--关联Mybatis-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!-- 配置 Mapper 接口扫描 -->
    <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dongjixue.dao"/>
    </bean>
</beans>

注意

注 意 , 没 有 必 要 去 指 定 SqlSessionFactory 或 SqlSessionTemplate , 因 为 MapperScannerConfigurer 将会创建 MapperFactoryBean,之后自动装配。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值