机缘巧合接触到国产轻量级持久层开源框架MiniDao,了解该框架也有一段时间了,但是一直都没有深入的研究底层代码,最近花了一些时间研究了一下实现原理。MiniDao官方提供的版本不支持分布式事务,我在官方的MiniDao-pe-1.6版本上实现了该功能,满足了现有项目的需求。以下具体分析该功能的实现:
步骤:
一、现有的问题
二、深入解析源码,实现分库事务功能
三、单元测试
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
1、设置数据源,该功能是我为了实现分布式事务扩展的,官方代码中没有
setDynamicDataSource(dataSourceType);
2、状态SQL模板所需的参数
templateSql = installDaoMetaData(pageSetting, method, sqlParamsMap, args);
3、解析SQL模板,返回可执行SQL
String executeSql = parseSqlTemplate(method, templateSql, sqlParamsMap);
4、组装SQL占位符参数
Map<String, Object> sqlMap = installPlaceholderSqlParam(executeSql, sqlParamsMap);
5、执行SQL,获取SQL执行返回值
Object returnObj = getReturnMinidaoResult(dbType, pageSetting, method, executeSql, sqlMap);
该方法的完整代码如下:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取数据源类型
DataSourceType dataSourceType = DataSourceContextHolder.getDataSourceType();
// 返回结果
Object returnObj = null;
// SQL模板
String templateSql = null;
// SQL模板参数
Map<String, Object> sqlParamsMap = new HashMap<String, Object>();
// 分页参数
MiniDaoPage pageSetting = new MiniDaoPage();
// 设置数据源
setDynamicDataSource(dataSourceType);
// Step.0 判断是否是Hiber实体维护方法,如果是执行Hibernate方式实体维护
// Map<String, Object> rs = new HashMap<String, Object>();
// Step.1装载SQL模板,所需参数
templateSql = installDaoMetaData(pageSetting, method, sqlParamsMap, args);
// Step.3解析SQL模板,返回可执行SQL
String executeSql = parseSqlTemplate(method, templateSql, sqlParamsMap);
// Step.4 组装SQL占位符参数
Map<String, Object> sqlMap = installPlaceholderSqlParam(executeSql, sqlParamsMap);
// Step.5 获取SQL执行返回值
try {
returnObj = getReturnMinidaoResult(dbType, pageSetting, method, executeSql, sqlMap);
} catch (Exception e) {
returnObj = null;
if(e instanceof EmptyResultDataAccessException){
//数据查询为空,不抛出Spring异常
}else{
e.printStackTrace();
throw e;
}
}
if (showSql) {
// System.out.println("MiniDao-SQL:\n\n" + executeSql);
logger.info("MiniDao-SQL:\n\n" + executeSql);
}
return returnObj;
}
/**
* 动态设置数据源
* @param dataSourceType
*/
@SuppressWarnings("static-access")
private void setDynamicDataSource(DataSourceType dataSourceType) {
if(dataSourceType != null) {
namedParameterJdbcTemplate.setDataSource((DataSource)appContext.getBean(dataSourceType.toString()));
jdbcTemplate.setDataSource((DataSource)appContext.getBean(dataSourceType.toString()));
}
}
该方法的作用是,根据设置数据源的类型,动态的修改namedParameterJdbcTemplate和jdbcTemplate的dataSource值。NamedParameterJdbcTemplate类是重写spring的,内部增加了setDataSource方法,在applicationContext.xml配置文件中也是配置的该bean。
<!-- JDBC配置,在MiniDaoHandler中需要使用该配置,并且根据数据源类型动态修改dataSource -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<!-- JDBC 占位符配置,在MiniDaoHandler中需要使用该配置,并且根据数据源类型动态修改dataSource -->
<bean id="namedParameterJdbcTemplate"
class="org.jeecgframework.minidao.datasource.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
WebApplicationContext类也是新扩展的类,用于获取spring容器中创建的bean对象,官方代码中没有。
package org.jeecgframework.minidao.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class WebApplicationContext implements ApplicationContextAware{
protected static ApplicationContext appContext;
public void setApplicationContext(ApplicationContext app) throws BeansException {
this.appContext = app;
}
public static ApplicationContext getAppContext() {
return (appContext);
}
public static Object getBean(String beanName) {
return appContext.getBean(beanName);
}
}
该类需要在applicationContext.xml中进行配置:
<!-- spring容器工具类,必须配置 -->
<bean id="appContext" class="org.jeecgframework.minidao.util.WebApplicationContext" />
<?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"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
default-autowire="byName" default-lazy-init="false">
<!-- 使用AspectJ方式配置AOP -->
<aop:aspectj-autoproxy />
<!-- 使用annotation 自动注册bean,并检查@Required,@Autowired的属性已被注入 -->
<context:component-scan base-package="examples.*" />
<!-- 引入数据库属性文件 -->
<context:property-placeholder location="classpath:dbconfig.properties" />
<!-- 配置主-从数据源信息 -->
<!-- com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean -->
<bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close" abstract="true">
<!-- SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana] -->
<property name="xaDataSourceClassName" value="${jdbc.xaDataSourceClassName}" />
<property name="poolSize" value="10" />
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="30" />
<property name="borrowConnectionTimeout" value="60" />
<property name="reapTimeout" value="20" />
<property name="maxIdleTime" value="60" />
<property name="maintenanceInterval" value="60" />
<property name="loginTimeout" value="60" />
<property name="testQuery" value="${validationQuery}" />
</bean>
<bean id="dataSource_jeecg" parent="abstractXADataSource">
<property name="uniqueResourceName" value="masterDB" />
<property name="xaProperties">
<props>
<prop key="driverClassName">${jdbc.driverClassName}</prop>
<prop key="url">${master.jdbc.url}</prop>
<prop key="password">${jdbc.password}</prop>
<!-- <prop key="user">${jdbc.username}</prop> --> <!-- mysql -->
<prop key="username">${jdbc.username}</prop> <!-- durid -->
<prop key="initialSize">2</prop>
<prop key="maxActive">20</prop> <!-- 若不配置则代码执行"{dataSource-1} inited"此处停止 -->
<prop key="minIdle">0</prop>
<prop key="maxWait">60000</prop>
<prop key="validationQuery">${validationQuery}</prop>
<prop key="testOnBorrow">false</prop>
<prop key="testOnReturn">false</prop>
<prop key="testWhileIdle">true</prop>
<prop key="removeAbandoned">true</prop>
<prop key="removeAbandonedTimeout">1800</prop>
<prop key="logAbandoned">true</prop>
<prop key="filters">mergeStat</prop>
</props>
</property>
</bean>
<bean id="mapdataSource" parent="abstractXADataSource">
<property name="uniqueResourceName" value="slaveDB" />
<property name="xaProperties">
<props>
<prop key="driverClassName">${jdbc.driverClassName}</prop>
<prop key="url">${slave.jdbc.url}</prop>
<prop key="password">${jdbc.password}</prop>
<!-- <prop key="user">${jdbc.username}</prop> -->
<prop key="username">${jdbc.username}</prop>
<prop key="initialSize">2</prop>
<prop key="maxActive">20</prop>
<prop key="minIdle">0</prop>
<prop key="maxWait">60000</prop>
<prop key="validationQuery">${validationQuery}</prop>
<prop key="testOnBorrow">false</prop>
<prop key="testOnReturn">false</prop>
<prop key="testWhileIdle">true</prop>
<prop key="removeAbandoned">true</prop>
<prop key="removeAbandonedTimeout">1800</prop>
<prop key="logAbandoned">true</prop>
<prop key="filters">mergeStat</prop>
</props>
</property>
</bean>
<!-- JDBC配置,在MiniDaoHandler中需要使用该配置,并且根据数据源类型动态修改dataSource -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
<!-- JDBC 占位符配置,在MiniDaoHandler中需要使用该配置,并且根据数据源类型动态修改dataSource -->
<bean id="namedParameterJdbcTemplate"
class="org.jeecgframework.minidao.datasource.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<!-- atomikos事务管理器 -->
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
<property name="forceShutdown">
<value>true</value>
</property>
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
<!-- spring 事务管理器 -->
<bean id="springTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
<!-- 必须设置,否则程序出现异常 JtaTransactionManager does not support custom isolation levels by default -->
<property name="allowCustomIsolationLevels" value="true"/>
</bean>
<!-- 数据源集合,可以配置多个数据源,不能在一个事务内动态设置数据源,否则不起作用 -->
<bean id="dataSource" class="org.jeecgframework.minidao.datasource.DynamicDataSource">
<property name="targetDataSources">
<!-- 注意:entry实体的key值与value-ref值要保持一致,否则在动态切换数据源时不起作用 -->
<map key-type="org.jeecgframework.minidao.datasource.DataSourceType">
<entry key="dataSource_jeecg" value-ref="dataSource_jeecg" />
<entry key="mapdataSource" value-ref="mapdataSource" />
</map>
</property>
<!-- 默认数据源 dataSource_jeecg -->
<property name="defaultTargetDataSource" ref="dataSource_jeecg" />
</bean>
<!-- 事务管理 -->
<tx:advice id="springTxAdvice" transaction-manager="springTransactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="create*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception" />
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:advisor advice-ref="springTxAdvice" pointcut="execution(* examples..service..*.*(..))" />
</aop:config>
<!-- spring容器工具类,必须配置 -->
<bean id="appContext" class="org.jeecgframework.minidao.util.WebApplicationContext" />
<!-- minidao拦截器 -->
<bean name="minidaoInterceptor" class="org.jeecgframework.minidao.aspect.MinidaoInterceptor"></bean>
<!-- MiniDao扫描类 -->
<bean class="org.jeecgframework.minidao.factory.MiniDaoBeanScannerConfigurer">
<!-- 是使用什么字母做关键字Map的关键字 默认值origin 即和sql保持一致,lower小写(推荐),upper 大写 -->
<property name="keyType" value="lower"></property>
<!-- 格式化sql -->
<property name="formatSql" value="true"></property>
<!-- 输出sql -->
<property name="showSql" value="true"></property>
<!-- 数据库类型 -->
<property name="dbType" value="mysql"></property>
<!-- dao地址,配置符合spring方式 -->
<property name="basePackage" value="examples.dao"></property>
<!-- 使用的注解,默认是Minidao,推荐 Repository -->
<property name="annotation" value="org.springframework.stereotype.Repository"></property>
<!-- Minidao拦截器配置 -->
<property name="emptyInterceptor" ref="minidaoInterceptor"></property>
</bean>
</beans>
#mysql \u6570\u636e\u5e93\u8fde\u63a5\u53c2\u6570
validationQuery=SELECT 1
jdbc.initialSize=5
jdbc.maxActive=20
jdbc.maxWait=60000
jdbc.poolPreparedStatements=false
jdbc.poolMaximumIdleConnections=0
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.xaDataSourceClassName=com.alibaba.druid.pool.xa.DruidXADataSource
#1.tms business. 2.The db level optimization,data concurrency,desirable.
master.jdbc.url=jdbc:mysql://localhost:3306/master?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
slave.jdbc.url=jdbc:mysql://localhost:3306/slave?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc.username=root
jdbc.password=root
#jta startup param
com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
com.atomikos.icatch.console_file_name = tx.out.log
com.atomikos.icatch.log_base_name = txlog
com.atomikos.icatch.tm_unique_name = com.atomikos.spring.jdbc.tm
com.atomikos.icatch.console_log_level=DEBUG
package examples.entity;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* 实体定义规则 字段不允许存在基本类型,必须都是包装类型(因为基本类型有默认值) 基本数据类型 包装类 byte Byte boolean Boolean
* short Short char Character int Integer long Long float Float double Double
*
* @author Administrator
*
*/
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String name;
private String empno;
private Integer age;
private BigDecimal salary;
private Date birthday;
private Date createDate;
private String createBy;
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmpno() {
return empno;
}
public void setEmpno(String empno) {
this.empno = empno;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public BigDecimal getSalary() {
return salary;
}
public void setSalary(BigDecimal salary) {
this.salary = salary;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", empno=" + empno + ", age=" + age + ", salary=" + salary
+ ", birthday=" + birthday + ", createDate=" + createDate + ", createBy=" + createBy + "]";
}
}
package examples.dao;
import java.util.List;
import java.util.Map;
import org.jeecgframework.minidao.annotation.Arguments;
import org.jeecgframework.minidao.annotation.Param;
import org.jeecgframework.minidao.annotation.ResultType;
import org.jeecgframework.minidao.annotation.Sql;
import org.jeecgframework.minidao.pojo.MiniDaoPage;
import org.springframework.stereotype.Repository;
import examples.entity.Employee;
@Repository
public interface EmployeeDao {
/**
* 返回记录总数
* @return
*/
@Sql("select count(*) from employee")
Integer getCount();
/**
* 插入数据
* @param employee
* @return
*/
@Arguments("employee")
Integer insertEmployee(Employee employee);
/**
* 更新数据
* @param employee
* @return
*/
Integer updateEmployee(@Param("employee") Employee employee);
/**
* 删除数据
* @param employee
* @return
*/
@Arguments({"employee"})
Integer deleteEmployee(Employee employee);
/**
* 查询返回单个Java对象
* @param id
* @return
*/
@Arguments({"id"})
Employee getEmployeeById(String id);
/**
* 返回List<Object> 类型的全部数据
* @return
*/
List<Employee> getAllEmployee();
/**
* 查询返回单个Map对象
* @param empno
* @param name
* @return
*/
Map<String, Object> getMap(@Param("empno") String empno, @Param("name") String name);
/**
* 返回List<Map> 类型全部数据
* @return
*/
List<Map<String, Object>> getAllListMap();
/**
* 通用分页方法,支持(oracle、mysql、SqlServer、postgresql)
* @param employee
* @param page
* @param rows
* @return
*/
@Arguments({"employee", "page", "rows"})
@ResultType(Employee.class)
MiniDaoPage<Employee> getPageEmployees(Employee employee, int page, int rows);
}
package examples.service;
import org.jeecgframework.minidao.datasource.DataSourceContextHolder;
import org.jeecgframework.minidao.datasource.DataSourceType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import examples.dao.EmployeeDao;
import examples.entity.Employee;
@Service
public class EmployeeService {
@Autowired
private EmployeeDao employeeDao;
public Employee selectEmployeeById(String id) {
DataSourceContextHolder.setDataSourceType(DataSourceType.mapdataSource);
return employeeDao.getEmployeeById(id);
}
public boolean registerMember(Employee employee1, Employee employee2) {
boolean resRegister = false;
try {
employeeDao.insertEmployee(employee1);
DataSourceContextHolder.setDataSourceType(DataSourceType.mapdataSource);
// employee2.setId(null);
employeeDao.insertEmployee(employee2);
resRegister = true;
} catch(Exception e) {
e.printStackTrace();
throw e;
}
return resRegister;
}
}
delete from employee
where 1=1
<#if employee.id?exists>
and id = :employee.id
</#if>
<#if employee.name?exists>
and name = :employee.name
</#if>
<#if employee.age?exists>
and age = :employee.age
</#if>
<#if employee.salary?exists>
and salary = :employee.salary
</#if>
<#if employee.empno?exists>
and empno = :employee.empno
</#if>
<#if employee.birthday?exists>
and birthday = :employee.birthday
</#if>
select * from employee
select * from employee
select * from employee where id=:id
select * from employee
where
empno = :empno
and name = :name
<#if employee.id?exists>
and id = '${employee.id}'
</#if>
<#if employee.name?exists>
and name = '${employee.name}'
</#if>
<#if employee.age?exists>
and age = ${employee.age}
</#if>
<#if employee.salary?exists>
and salary = ${employee.salary}
</#if>
<#if employee.empno?exists>
and empno = '${employee.empno}'
</#if>
<#if employee.birthday?exists>
and birthday = :employee.birthday
</#if>
select * from (SELECT * FROM employee where 1=1
<#include "EmployeeDao_getPageEmployees_conditions.sql">
) a
where 1=1
<#include "EmployeeDao_getPageEmployees_conditions.sql">
insert into employee(id,name,empno,age,salary,birthday,create_date,create_by)
values(
'${employee.id}',
'${employee.name}',
'${employee.empno}',
${employee.age},
${employee.salary},
:employee.birthday,
:employee.createDate,
'${employee.createBy}'
)
<#if employee.name?exists>
name = :employee.name,
</#if>
<#if employee.age?exists>
age = :employee.age,
</#if>
<#if employee.salary?exists>
salary = :employee.salary,
</#if>
<#if employee.empno?exists>
empno = :employee.empno,
</#if>
<#if employee.birthday?exists>
birthday = :employee.birthday,
</#if>
<#if employee.createDate?exists>
create_date = :employee.createDate,
</#if>
<#if employee.createBy?exists>
create_by = :employee.createBy,
</#if>
update employee set
<#include "EmployeeDao_updateEmployee_conditions.sql">
where id = :employee.id
package org.springframework.test.context.junit4;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.runner.RunWith;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import org.springframework.test.context.web.ServletTestExecutionListener;
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({ ServletTestExecutionListener.class, DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class })
public abstract class AbstractJUnit4SpringContextTests implements ApplicationContextAware {
protected final Log logger = LogFactory.getLog(this.getClass());
protected ApplicationContext applicationContext;
public final void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
package test;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.jeecgframework.minidao.pojo.MiniDaoPage;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import examples.dao.EmployeeDao;
import examples.entity.Employee;
import examples.service.EmployeeService;
import test.spring.SpringTxTestCase;
public class EmployeeDaoJunit extends SpringTxTestCase {
@Autowired
EmployeeDao employeeDao;
@Autowired
EmployeeService employeeService;
/**
* 测试MiniDao分布式事务,同时向连个数据库中插入数据,当数据库A成功,数据库B失败时,数据库A插入的记录也会被回滚
*/
@Test
public void testRegister() {
Employee employee = new Employee();
employee.setId("11");
employee.setName("王老七2");
employee.setAge(51);
employee.setEmpno("010");
employee.setSalary(new BigDecimal(11200.00));
employee.setBirthday(new Date());
boolean result = employeeService.registerMember(employee, employee);
System.out.println(result);
}
/**
* 测试MiniDao的@Sql标签
*/
@Test
public void testCount() {
System.out.println("-------------testCount----------------------");
int count = employeeDao.getCount();
System.out.println(count);
}
/**
* 测试MiniDao的插入方法
*/
@Test
public void testInsertEmployee() {
System.out.println("-------------testInsertEmployee----------------------");
Employee employee = new Employee();
employee.setId("8");
employee.setName("谢永强");
employee.setAge(30);
employee.setEmpno("010");
employee.setSalary(new BigDecimal(4500.00));
employee.setBirthday(new Date());
int rows = employeeDao.insertEmployee(employee);
System.out.println(rows);
}
/**
* 测试MiniDao的修改方法
*/
@Test
public void testUpdateEmployee() throws ParseException {
System.out.println("-------------testUpdateEmployee----------------------");
Employee employee = employeeDao.getEmployeeById("1");
Date birthday = new SimpleDateFormat("yyyy-MM-dd").parse("1994-09-03");
employee.setBirthday(birthday);
employee.setName("刘彦民");
int rows = employeeDao.updateEmployee(employee);
System.out.println(rows);
}
/**
* 测试MiniDao查找返回单个实体对象
* 测试在事务中动态修改数据源,service层
*/
@Test
public void testGetEmployeeById() {
System.out.println("-------------testGetEmployeeById----------------------");
// DataSourceContextHolder.setDataSourceType(DataSourceType.mapdataSource);
Employee employee = employeeService.selectEmployeeById("1");
System.out.println("name: " + employee.getName());
System.out.println("age: " + employee.getAge());
System.out.println("salary: " + employee.getSalary());
System.out.println("empno: " + employee.getEmpno());
}
/**
* 测试MiniDao删除方法
*/
@Test
public void testDeleteById() {
System.out.println("-------------testDeleteById----------------------");
Employee employee = new Employee();
employee.setId("9");
int rows = employeeDao.deleteEmployee(employee);
System.out.println(rows);
}
/**
* 测试MiniDao查询返回实体列表
*/
@Test
public void testGetAllEmployee() {
System.out.println("-------------testGetAllEmployee----------------------");
List<Employee> employees = employeeDao.getAllEmployee();
for(Employee employee : employees) {
System.out.println("name: " + employee.getName() + ",age: " + employee.getAge() + ",salary: " + employee.getSalary());
}
}
/**
* 测试MiniDao查询返回单个Map对象
*/
@Test
public void testGetMap() {
System.out.println("-------------testGetMap----------------------");
Map<String, Object> map = employeeDao.getMap("005", "王馨");
System.out.println(map);
}
/**
* 测试MiniDao查询返回Map对象列表
*/
@Test
public void testGetAllListMap() {
System.out.println("-------------testGetAllListMap----------------------");
List<Map<String, Object>> list = employeeDao.getAllListMap();
for(Map<String, Object> l : list) {
System.out.println(l);
}
}
/**
* 测试MiniDao分页查询
*/
@Test
public void testGetPageEmployees() {
System.out.println("-------------testGetPageEmployees----------------------");
Employee employee = new Employee();
employee.setAge(20);
MiniDaoPage<Employee> employeePage = employeeDao.getPageEmployees(employee, 1, 2);
System.out.println("pages: " + employeePage.getPages() + ", page: " + employeePage.getPage() + ", total: " + employeePage.getTotal() + ", rows: " + employeePage.getRows());
System.out.println(employeePage.getResults());
}
}