对返回值的处理
有些sql查询会返回一些复杂类型,这些复杂类型没有办法简单的通过xml或者注解配置来实现,这种时候我们需要实现mybatis 的ResultHandler接口,来做自定义的对象属性映射。
ResultHandler例子:
Mybatis在调用ResultHandler的handleResult(ResultContext)方法之后生成bean,首先我们定义一个复杂对象。
public interface GrandFatherMapper {
public static class GrandFatherWithGrandChildren {
public GrandFather grandFather;
public Child child;
}
public void selectComplex(ResultHandler handler);
}
com.xxx.xxx.BaseResultMap是另一个实体的mapper的resultMap。
这个查询,返回的每一条记录都是
{key=..., value=...}
这个结果集并不符合要求。不过通过ResultHandler来处理每一条记录就可以达到要求了。
看下Mybatis源码里面有关继承ResultHandler的DefaultMapResultHandler类。
public class DefaultMapResultHandler<K, V> implements ResultHandler {
private final Map<K, V> mappedResults;
private final String mapKey;
@SuppressWarnings("unchecked")
public DefaultMapResultHandler(String mapKey, ObjectFactory objectFactory) {
this.mappedResults = objectFactory.create(Map.class);
this.mapKey = mapKey;
}
public void handleResult(ResultContext context) {
// TODO is that assignment always true?
final V value = (V) context.getResultObject();
final MetaObject mo = MetaObject.forObject(value);
// TODO is that assignment always true?
final K key = (K) mo.getValue(mapKey);
mappedResults.put(key, value);
}
public Map<K, V> getMappedResults() {
return mappedResults;
}
}
这个DefaultMapResultHandler实现handleResult接口,处理每条数据。
可以模仿这个类写个类来装配自己所需要的Map。
private class MapResultHandler implements ResultHandler {
@SuppressWarnings("rawtypes")
private final Map mappedResults = new HashMap();
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void handleResult(ResultContext context) {
Map map = (Map) context.getResultObject();
mappedResults.put(map.get("key"), map.get("value"));
}
public Map getMappedResults() {
return mappedResults;
}
}
this.getSqlSession().select(getWholeSqlId("getUaMapByTimestamp"),handler);
这样就可以得到需要的结果集了。
使用自定义的数据库源
Mybatis支持使用自定义的数据源,这里我们使用HikariDataSourceFactory举例
首先需要在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>
<typeAlias type='com.xxx.xxx.xxx.HikariDataSourceFactory' alias='HikariDataSourceFactory'/>
</typeAliases>
...
<environments default='development'>
<environment id='development'>
<transactionManager type='JDBC'/>
<dataSource type='HikariDataSourceFactory'>
<property name="mysql.driverClassName" value="${mysql.driverClassName}"/>
<property name="mysql.jdbcUrl" value="${mysql.jdbcUrl}"/>
<property name="mysql.username" value="${mysql.username}"/>
<property name="mysql.password" value="${mysql.password}"/>
<property name="mysql.maximumPoolSize" value="${mysql.maximumPoolSize}"/>
<property name="mysql.autoCommit" value="${mysql.autoCommit}"/>
<property name="mysql.cachePrepStmts" value="${mysql.cachePrepStmts}"/>
<property name="mysql.prepStmtCacheSize" value="${mysql.prepStmtCacheSize}"/>
<property name="mysql.prepStmtCacheSqlLimit" value="${mysql.prepStmtCacheSqlLimit}"/>
</dataSource>
</environment>
</environments>
...
</configuration>
然后我们实现DataSourceFactory方法,mybatis会在加载xml配置文件时,使用我们设置好的数据源
public class HikariDataSourceFactory implements DataSourceFactory {
private Properties properties;
private static final Logger LOGGER = LoggerFactory.getLogger(HikariDataSourceFactory.class);
@Override
public void setProperties(Properties props) {
this.properties = props;
}
@Override
public DataSource getDataSource() {
try {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl(properties.getProperty(MySQLDAOFactory.CONF_JDBC_URL, ""));
hikariConfig.setUsername(properties.getProperty(MySQLDAOFactory.CONF_USERNAME, ""));
hikariConfig.setPassword(properties.getProperty(MySQLDAOFactory.CONF_PASSWORD, ""));
hikariConfig.setMaximumPoolSize(Integer.parseInt(properties.getProperty(MySQLDAOFactory.CONF_MAX_POOLSIZE, "10")));
hikariConfig.setAutoCommit(Boolean.valueOf(properties.getProperty(MySQLDAOFactory.CONF_AUTO_COMMIT, "false")
));
hikariConfig.addDataSourceProperty("cachePrepStmts",
properties.getProperty(MySQLDAOFactory.CONF_CACHE_PREPARESTATEMENT, "true"));
hikariConfig.addDataSourceProperty("prepStmtCacheSize",
properties.getProperty(MySQLDAOFactory.CONF_PREPARESTATEMENT_CACHE_SIZE, "300"));
hikariConfig.addDataSourceProperty("prepStmtCacheSqlLimit",
properties.getProperty(MySQLDAOFactory.CONF_PREPARESTATEMENT_CACHE_LIMIT, "2048"));
return new HikariDataSource(hikariConfig);
} catch (Exception e) {
LOGGER.error("create HikariConfig data source error {} ", e);
}
return null;
}
}
接下来在初始化函数中调用。
public void init(ServiceConfig config) {
try {
Properties properties = new Properties();
properties.setProperty(MySQLDAOFactory.CONF_DRIVER_CLASSNAME, config.getConfig(MySQLDAOFactory.CONF_JDBC_URL, "com.mysql.cj.jdbc.Driver"));
properties.setProperty(MySQLDAOFactory.CONF_JDBC_URL, config.getConfig(MySQLDAOFactory.CONF_JDBC_URL, ""));
properties.setProperty(MySQLDAOFactory.CONF_USERNAME, config.getConfig(MySQLDAOFactory.CONF_USERNAME, ""));
properties.setProperty(MySQLDAOFactory.CONF_PASSWORD, config.getConfig(MySQLDAOFactory.CONF_PASSWORD, ""));
properties.setProperty(MySQLDAOFactory.CONF_MAX_POOLSIZE, config.getConfig(MySQLDAOFactory.CONF_MAX_POOLSIZE, "10"));
properties.setProperty(MySQLDAOFactory.CONF_AUTO_COMMIT, config.getConfig(MySQLDAOFactory.CONF_AUTO_COMMIT, "false"));
properties.setProperty(MySQLDAOFactory.CONF_CACHE_PREPARESTATEMENT, config.getConfig(MySQLDAOFactory.CONF_CACHE_PREPARESTATEMENT, "true"));
properties.setProperty(MySQLDAOFactory.CONF_PREPARESTATEMENT_CACHE_SIZE, config.getConfig(MySQLDAOFactory.CONF_PREPARESTATEMENT_CACHE_SIZE, "300"));
properties.setProperty(MySQLDAOFactory.CONF_PREPARESTATEMENT_CACHE_LIMIT, config.getConfig(MySQLDAOFactory.CONF_PREPARESTATEMENT_CACHE_LIMIT, "2048"));
try (Reader reader = Resources.getResourceAsReader("mybatis-config.xml")) {
factory = new SqlSessionFactoryBuilder().build(reader, properties);
LOGGER.info("mybatis init success.");
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
} catch (Exception e) {
LOGGER.error("MyBatisSqlSession init failed ", e);
}
}