SpringBoot学习日记三(整合mybatis使用传统的SqlSessionTemplate来实现通用Dao操作)

在学习日记二中,我们springbot+mybatis实现是通过mapper接口,mapper.xml。每一个的mapper.xml都对应一个mapper接口,我们的service调用的时候也是调用对应的mapper接口然后去操作数据库。所以当数据库的表多的情况或者sql语句复杂的情况下,为了项目的维护方便。以及不必需要那么多的mapper接口。

所以我们可以通过传统的SqlSessionTemplate来实现一个通用的Dao对mapper.xml直接操作。直接不需要mapper接口层。不通过mapper接口层来执行对应sql。直接使用通用的Dao来调用。

既然不需要mapper接口了。所以我们把SpringBootDemoApplication项目启动类扫描mapper接口的@MapperScan注释掉,如果没有再启动类里面写@MapperScan而是单独写@Mapper,请把@Mapper注释掉。

package com.lds.springbootdemo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;

@SpringBootApplication
/*直接在Mapper类上面添加注解@Mapper,这种方式要求每一个mapper类都需要添加此注解,麻烦
  所以可以通过使用@MapperScan可以指定要扫描的Mapper类的包的路径
 */
//注释掉
//@MapperScan("com.lds.springbootdemo.mapper")
// 用来指定配置文件的位置
@PropertySource(value={"classpath:dbconfig.properties"})
public class SpringBootDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemoApplication.class, args);
    }

}

此时我们就可以删除mapper接口了。删不删都行,反正现在注释掉了@MapperScan或者@Mapper。

注意此处一个坑!!!

亲身实践,说多了都是泪啊(⊙﹏⊙)。注释掉了@MapperScan或者@Mapper之后,如果你没有删除mapper接口的java文件。如果原来在****mapper.java接口文件写的有@Select、@Update,@Insert、@dalete等注解,一定也要注释掉。不然就会报如下的错,会根据项目来变,所以我就把报错信息的变量替换成了

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '***': Unsatisfied dependency expressed through field '***'; 
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '***': Unsatisfied dependency expressed through field '***'; 
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '***': Unsatisfied dependency expressed through field 'sqlSessionTemplate';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sqlSessionTemplate' defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]: Unsatisfied dependency expressed through method 'sqlSessionTemplate' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]: Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file ***'; nested exception is java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.lds.repastsystem.mapper.employeeMapper.selectByAccount. please check file [***] and ***Mapper.java (best guess)

解决办法:

  1. 删除mapper.java接口
  2. 注释掉****mapper.java接口文件写的有@Select、@Update,@Insert、@dalete等注解

 

然后我们application.properties项目配置文件中的mybatis的mapper映射路径必须要写

#设置项目访问名称
server.servlet.context-path=/springBootDemo
#mysql数据源配置
spring.datasource.driver-class-name=${driverClass}
spring.datasource.url=${url}
spring.datasource.username=${user}
spring.datasource.password=${password}
#mybatis的mapper映射路径
mybatis.mapperLocations=classpath:mybatis/mapper/*.xml

之后的操作就是进行编写Dao。

在com.lds.repastsystem包下新建一个dao包。然后编写Dao的接口的实现类。

Dao.java

package com.lds.springbootdemo.dao;

/**
 * @program: springbootdemo
 * @description:
 * @author:
 * @createData: 
 * @updateAuthor:
 * @updateData: 
 * @updateContent:
 * @Version: 1.0
 * @email: lidongshenglife@163.com
 * @blog: www.b0c0.com
 */


public interface Dao {
    /**
     * 保存对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object save(String str, Object obj) throws Exception;

    /**
     * 修改对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object update(String str, Object obj) throws Exception;

    /**
     * 删除对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object delete(String str, Object obj) throws Exception;

    /**
     * 查找返回一个对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object selectForOne(String str, Object obj) throws Exception;
    /**
     * 查找返回多个对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object selectForList(String str, Object obj) throws Exception;

}

DaoSupport.java

package com.lds.springbootdemo.dao;

import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * @program: springbootdemo
 * @description:
 * @author:
 * @createData: 
 * @updateAuthor:
 * @updateData: 
 * @updateContent:
 * @Version: 1.0
 * @email: lidongshenglife@163.com
 * @blog: www.b0c0.com
 */
/*
注解了@Repository的类上如果数据库操作中抛出了异常,就能对其进行处理,
转而抛出的是翻译后的spring专属数据库异常,方便我们对异常进行排查处理)。
 */
@Repository
/*
加入 @Transactional 注解,使用默认配置,抛出异常之后,事务会自动回滚,数据不会插入到数据库。
 */
@Transactional
public class DaoSupport implements Dao {

    /**
     * @Autowired默认按类型装配(这个注解是属于spring的),
     * 默认情况下必须要求依赖对象必须存在,如果要允许null值,
     * 可以设置它的required属性为false,如:@Autowired(required=false) ,
     * 如果我们想使用名称装配可以结合@Qualifier注解进行使用 @Autowired()@Qualifier("baseDao")
     * @Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,
     * 如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,
     * 如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。
     * 但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
     */
    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;
    /**
     * 保存对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object save(String str, Object obj) throws Exception {
        return sqlSessionTemplate.insert(str, obj);
    }

    /**
     * 批量更新
     * @param str
     * @param objs
     * @return
     * @throws Exception
     */
    public Object batchSave(String str, List objs)throws Exception{
        return sqlSessionTemplate.insert(str, objs);
    }

    /**
     * 修改对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object update(String str, Object obj) throws Exception {
        return sqlSessionTemplate.update(str, obj);
    }

    /**
     * 批量更新
     * @param str
     * @param objs
     * @return
     * @throws Exception
     */
    public void batchUpdate(String str, List objs)throws Exception{
        SqlSessionFactory sqlSessionFactory = sqlSessionTemplate.getSqlSessionFactory();
        //批量执行器
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
        try{
            if(objs!=null){
                for(int i=0,size=objs.size();i<size;i++){
                    sqlSession.update(str, objs.get(i));
                }
                sqlSession.flushStatements();
                sqlSession.commit();
                sqlSession.clearCache();
            }
        }finally{
            sqlSession.close();
        }
    }
    /**
     * 删除对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object delete(String str, Object obj) throws Exception {
        return sqlSessionTemplate.delete(str, obj);
    }
    /**
     * 批量删除
     * @param str
     * @param objs
     * @return
     * @throws Exception
     */
    public Object batchDelete(String str, List objs )throws Exception{
        return sqlSessionTemplate.delete(str, objs);
    }

    /**
     * 查找返回一个对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object selectForOne(String str, Object obj){
        return sqlSessionTemplate.selectOne(str, obj);
    }
    /**
     * 查找返回多个对象
     * @param str
     * @param obj
     * @return
     * @throws Exception
     */
    public Object selectForList(String str, Object obj){
        return sqlSessionTemplate.selectList(str, obj);
    }
}

里面有两个参数,第一个参数就直接填希望去执行mapper.xml中的sql。第二个就是我们需要sql中需要传递的参数。就好比登录验证实例来说:

sbd_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.lds.springbootdemo.mapper.sbd_userMapper">
  *****省略部分内容*****
  <select id="selectByAccount" parameterType="java.lang.String" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from sbd_user
    where Account = #{account,jdbcType=VARCHAR}
  </select>
  *****省略部分内容*****
</mapper>

mapper标签的namespace属性的值:com.lds.springbootdemo.mapper.sbd_userMapper

执行的sqlId的值:selectByAccount

我们的第一个参数就是:

com.lds.springbootdemo.mapper.sbd_userMapper.selectByAccount

注意此处一个坑!!!

亲身实践,说多了都是泪啊(⊙﹏⊙)。第一个参数一定要和mapper标签的namespace属性的值相对应,不能直接写成sbd_userMapper.selectByAccount!!!因为我就犯了这样的错误。导致报了这样一个错

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for ***
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for *** 

*** 在我这个项目里指的是sbd_userMapper.selectByAccount,

之后让我找很长时间的原因,最后一步一步debug进入源码调试看到才发现必须要和namespace属性的值一致。不能省略前面的内容。

解决办法:

  1. 调用的时候参数写完整com.lds.springbootdemo.mapper.sbd_userMapper.selectByAccount
  2. 如果不想写com.lds.springbootdemo.mapper前面的这一串的话,可以直接把mapper.xml的mapper标签的namespace属性的值改成namespace=”sbd_userMapper”即可,调用的时候参数就直接写成sbd_userMapper.selectByAccount即可。

 

然后就是lognService去通过调用通用Dao。

LoginServiceImpl.java

package com.lds.springbootdemo.service.login_register;

import com.lds.springbootdemo.dao.DaoSupport;
import com.lds.springbootdemo.domain.sbd_user;
import com.lds.springbootdemo.mapper.sbd_userMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @program: springbootdemo
 * @description:
 * @author:
 * @createData: 
 * @updateAuthor:
 * @updateData: 
 * @updateContent:
 * @Version: 1.0
 * @email: lidongshenglife@163.com
 * @blog: www.b0c0.com
 */

@Service
public class LoginServiceImpl implements LoginService {

    //@Autowired
    //private sbd_userMapper userMapper;
    @Autowired
    private DaoSupport dao;
    /**
     * 登录验证Service
     * @return
     */
    @Override
    public boolean loginValidate(String account,String password) {
        boolean retu=false;
        //sbd_user em=userMapper.selectByAccount(account);
        sbd_user user= null;
        try {
            user = (sbd_user) dao.selectForOne("sbd_userMapper.selectByAccount",account);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(user!=null&&password.equals(user.getPassword())){
            retu=true;
        }
        return retu;
    }
}

然后就可以实现了,这样的话不管以后有多少模块功能,只要和数据库的操作直接调用这个通用Dao就行,不必再写很多的Mapper.java接口文件。

我已经把这个的实例放在github中了~~~地址:

https://github.com/DeBug-Bug/springBootDemo.git

发表评论

电子邮件地址不会被公开。