Mybatis 中如何通过SqlSessionDaoSupport来手动实现DAOis

MyBatis

1. 前言

在 MyBatis 中,当我们编写好访问数据库的映射器接口后,MapperScannerConfigurer 就能自动成批地帮助我们根据这些接口生成 DAO 对象,然后我们再使用 Spring 把这些 DAO 对象注入到业务逻辑层的对象( Service 类的对象)。因此,在这种情况下的 DAO 层,我们几乎不用编写代码,而且也没有地方编写,因为只有接口。这固然方便,不过如果我们需要在 DAO 层写一些代码的话,这种方式就无能为力了。此时, MyBatis-Spring 提供给我们的 SqlSessionDaoSupport类就派上了用场。

2. 认识 SqlSessionDaoSupport

org.mybatis.spring.support.SqlSessionDaoSupport 是spring-mybatis包下的类,继承了DaoSupport抽象类,作为DAO 的基类来使用。它需要一个 SqlSessionTemplate 或一个 SqlSessionFactory ,若两者都设置了,则 SqlSessionFactory 会被忽略(实际上它接收了 SqlSessionFactory 后也会利用factory创建一个 SqlSessionTemplate )。

这样,我们在子类中就能通过调用 SqlSessionDaoSupport类的 getSqlSession()方法来获取这个 SqlSessionTemplate 对象。而 SqlSessionTemplate 类实现了 SqlSession 接口,因此,有了 SqlSessionTemplate 对象,访问数据库就不在话下了。所以,我们需要 Spring 给 SqlSessionDaoSupport 类的子类的对象(多个 DAO 对象)注入一个 SqlSessionFactory 或一个 SqlSessionTemplate 。好消息是, SqlSessionTemplate 是线程安全的,因此,给多个 DAO 对象注入同一个 SqlSessionTemplate 是没有问题的,本例也将注入SqlSessionFactory 。

但坏消息是,自 mybatis-spring-1.2.0 以来, SqlSessionDaoSupport 的 setSqlSessionTemplatesetSqlSessionFactory 两个方法上的@Autowired 注解被删除,这就意味着继承于 SqlSessionDaoSupport 的 DAO 类,它们的对象不能被自动注入 SqlSessionFactory 或 SqlSessionTemplate 对象。如果在 Spring 的配置文件中一个一个地配置的话,显然太麻烦。比较好的解决办法是在我们的 DAO 类中覆盖这两个方法之一,并加上 @Autowired 注解。那么如果在每个 DAO 类中都这么做的话,显然很低效。更优雅的做法是,写一个继承于 SqlSessionDaoSupport 的BaseDao,在 BaseDao 中完成这个工作,然后其他的 DAO 类再都从 BaseDao 继承。

3. BaseDaoImpl

3.1 基于注解实现

继承spring 的SqlSessionDaoSupport,重写setSqlSessionTemplate()方法

public class BaseDaoImpl extends SqlSessionDaoSupport {
 
 @Autowired
 public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate)
    {
     super.setSqlSessionTemplate(sqlSessionTemplate);
    }
 
}

配置好SqlSessionFactory

<!-- mybatis配置 -->
<bean id="sqlSessionFactory" class="com.sas.core.spring.SasSqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
	<property name="mapperLocations" value="${mybatis.mapperLocations}" />
	<property name="configTypeAliasLocations" value="${mybatis.configLocation}" />
</bean>

3.2基于xml配置

利用spring的set注入实现

<bean id="baseSqlDao"  class="com.sas.core.dao.impl.sql.BaseDaoSqlImpl">
	<property name="sqlSessionFactory" ref="sqlSessionFactory" />
	<property name="sqlSessionTemplate" ref="sqlSessionTemplate" />
</bean>

必须事先配置好 SqlSessionFactorySqlSessionTemplate

<!-- mybatis配置 -->
<bean id="sqlSessionFactory" class="com.sas.core.spring.SasSqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource" />
	<property name="mapperLocations" value="${mybatis.mapperLocations}" />
	<property name="configTypeAliasLocations" value="${mybatis.configLocation}" />
</bean>

<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"
	scope="prototype">
	<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

3.3 加强 BaseDaoImpl

基于重构原则,我们可以在BaseDaoImpl内通过泛型创建通用方法,加强BaseDaoImpl
BaseMeta对应你实体类的基类

/***************
 * 所有dao实现的基类
 * @param <TObject>  实体类
 * @param <TId> 主键类型
 */
public class BaseDaoImpl<TObject extends BaseMeta, TId extends Object> extends SqlSessionDaoSupport 
	implements BaseDao<TObject, TId> {

	/***********
	 * get the class of meta
	 * @Title: getMetaClass
	 * 
	 * @return
	 * @throws
	 */
	@SuppressWarnings("rawtypes")
	protected Class getMetaClass() {
		throw new ServerUnknownException("please add method getMetaClass in subclass of BaseDaoSqlImpl!");
	}
	
	/******************
	 * 获取方法名
	 * @return
	 */
	private final String getMetaClassName(){
		return this.getMetaClass().getSimpleName();
	}
	
	/***************
	 * cachedao 已经实现了该方法
	 */
	public final String getTableName() {
		throw new UnsupportedOperationException("BaseDaoSqlImpl.getTableName is not supportted for" +
				" BaseCacheDaoImpl has already implementted this method!");
	}
	
	/*************
	 * 添加记录,成功返回对象, 否则返回null
	 * @param obj
	 * @return
	 */
	public final TObject add(TObject obj){
		if(obj == null){
			return  null;
		}
		if(getSqlSession().insert(this.getMetaClassName() + ".add", obj) > 0){
			return obj;
		}
		return null;
	}
	
	/***************
	 * 根据id获取对象
	 * @param id
	 * @return
	 */
	public final TObject getById(TId id){
		return getSqlSession().selectOne(this.getMetaClassName() + ".getById", id);
	}
	
	/**************
	 * 根据id列表获取批量对象
	 * @param ids
	 * @return
	 */
	public final List<TObject> listByIds(TId[] ids){
		if (ArrayUtils.isEmpty(ids)) {
			return Collections.emptyList();
		}
		List<TObject> tObjectList = this.getSqlSession().selectList(this.getMetaClassName() + ".listByIds", ids);
		return this.assureNotNullList(tObjectList);
	}
	
	/*************
	 * 根据id列表批量删除对象,返回删除的行数
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public final int deleteByIds(TId... ids)
	{
		if(ArrayUtils.isEmpty(ids)){
			return 0;
		}
		return getSqlSession().delete(this.getMetaClassName() + ".deleteByIds",ids);
	}
	
	/***************
	 * 确保返回的list不是null,以免nullpointexception
	 * @param list
	 * @return
	 */
	protected final <T> List<T> assureNotNullList(final List<T>  list){
		return list == null ?  new ArrayList<T>(0) : list;
	}
}

3.4 创建BaseDaoImpl的实现类

根据具体业务创建实现类,例如 UserDaoSqlImpl ,实现 UserDao 接口
具体SqlSession的用法可以看官方手册

public class UserDaoSqlImplextends BaseDaompl<User, Long> implements SasUserDao {
	@SuppressWarnings("rawtypes")
	@Override
	protected Class getMetaClass(){
		return SasUser.class;
	}
	@Override
	public boolean updateLastLoginTime(long userId,long newLoginTime) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("userId", userId);
		params.put("lastLoginTime", newLoginTime);
		//User 是UserMapper.xml的`namespace`属性,可以自定义
		//updateLastLoginTime 是UserMapper.xml的语句id
		return this.getSqlSession().update("User.updateLastLoginTime", params) > 0;
	}

3.5 剩余代码补齐

3.5.2 BaseDao
public interface BaseDao<TObject extends BaseMeta, TId extends Object> {

	/***************
	 * 获取表名
	 * @return
	 */
	public String getTableName();
	
	/*************
	 * 添加记录,成功返回对象, 否则返回null
	 * @param obj
	 * @return
	 */
	public TObject add(TObject obj);
	
	/***************
	 * 根据id获取对象
	 * @param id
	 * @return
	 */
	public TObject getById(TId id);
	
	/**************
	 * 根据id列表获取批量对象
	 * @param ids
	 * @return
	 */
	public List<TObject> listByIds(TId[] ids);
	
	/*************
	 * 根据id列表批量删除对象,返回删除的行数
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public int deleteByIds(TId... ids);
}
3.5.2 UserDao
public interface UserDao extends BaseDao<SasUser, Long>{
	boolean updateLastLoginTime(final long userId, final long newLoginTime);

3.5 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="User">
<update id="updateLastLoginTime" parameterType="map">
		UPDATE
			user
		SET
			lastLoginTime = #{lastLoginTime}
		WHERE
			id = #{id}
	</update>
</mapper>

4. 总结

至此,我们可以通过继承BaseDaoImpl来手动编写Dao,完美完结
撒花,结束~

附 : Junit 测试代码

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = {"classpath:application-context.xml"})
//@ContextConfiguration({"classpath:spring-context.xml","classpath:spring-context-druid.xml","classpath:spring-context-mybatis.xml"})
public class UserDaoTest {
	
	@Autowired
	private UserDao userDao;
	
	@Test
	public void TestAddUser(){
		Long loginTime= System.currentTimeMillis();
		Long id = 1L;
		if(!userDao.updateLastLoginTime(id ,loginTime);){
			System.out.println("Failed to updateLastLoginTime!");
			return;
		}
		System.out.println("Success to updateLastLoginTime! id : " + id );
	}
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个使用Mybatis-Plus进行通用DAO层封装的示例代码: 1. 首先,我们需要引入Mybatis-Plus依赖: ```xml <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> ``` 2. 接着,我们需要定义一个基础的Mapper接口,用于封装通用的增删改查操作: ```java import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface MyBaseMapper<T> extends BaseMapper<T> { } ``` 3. 然后,我们需要定义一个基础的Service接口,用于封装通用的增删改查操作: ```java import com.baomidou.mybatisplus.extension.service.IService; public interface MyBaseService<T> extends IService<T> { } ``` 4. 最后,我们需要定义一个基础的ServiceImpl实现类,用于实现通用的增删改查操作: ```java import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; public abstract class MyBaseServiceImpl<M extends MyBaseMapper<T>, T> extends ServiceImpl<M, T> implements MyBaseService<T> { } ``` 通过以上代码实现,我们可以很方便地使用Mybatis-Plus进行通用DAO层封装。接下来,我们只需要定义具体的Mapper和Service接口,继承以上基础接口即可,如: ```java public interface UserMapper extends MyBaseMapper<User> { } public interface UserService extends MyBaseService<User> { } public class UserServiceImpl extends MyBaseServiceImpl<UserMapper, User> implements UserService { } ``` 这样,我们就可以通过UserService接口,调用Mybatis-Plus提供的通用方法,实现对User表的增删改查操作了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值