最近有个项目的数据库使用postgresql,使用原生态的mybatis操作数据,原生态的没什么不好,只不过国内有个tk.mybatis的工具帮助我们做了很多实用的事情,大多数情况下我们需要在原生态mybatis上加工的想法它基本上都已经有很好的实现,这篇将分享安装postgresql,配置tk.mybatis的详细步骤以及在这过程中可能遇到的一些小问题。
- 安装postgresql,执行下面的命令就可以安装了:
apt-get update && apt-get install postgresql
服务端安装好之后我们还需要一个图形界面的客户端pdAdmin,我安装的是Windows版本的postgresql自带的,可以到这个地址找对应的版本。安装成功后默认会创建一个系统用户,一个数据库用户,名称以及密码都是postgres,我们可以新创建用户也可以直接使用这个帐号,反正我这只是测试。安装完成之后,可能会遇到远程访问问题:
远程连接问题,默认情况下只允许本地连接,要想允许其它客户端连接,我们可以修改它的配置文件,这个文件的目录位于/etc/postgresql/9.5/main,这个目录下有两个文件:
1:postgresql.conf,这个是服务器相关,里面有一个listen_address的地址,默认只监听本地,我们可以修改它。
2:pg_hba.cof,这个是用户权限相关,里面有一个与连接相关的配置,可以配置成网关模式
成功连接之后,大概是这个样子,我们可以创建数据库,表等对象。
mybatis代码生成器,数据库与Model的映射,这类机械的工作应该交给机器来完成,详细使用参考这里。
通用mapper,单表的CRUD操作可以抽像出一个公共接口,tk.mybatis提供的通用mapper可以帮助我们解决这类问题。
- mapper.xml,足够小(只包含字段映射)
<mapper namespace=“com.jim.logstashmvc.dao.generated.mapper.ProductMapper”>
<resultMap id=“BaseResultMap” type=“com.jim.logstashmvc.dao.generated.entity.Product”>
<id column=“id” jdbcType=“BIGINT” property=“id” />
<result column=“name” jdbcType=“VARCHAR” property=“name” />
</resultMap>
</mapper>
- mapper,足够简单(只需要继承通过mapper接口)
public interface ProductMapper extends Mapper
}
- 插件,这里有分页插件,SQL性能分析插件等,与mybatis集成非常容易。
如何与spring集成?
生成器的集成,可以采用maven方式来运行代码生成器
- 依赖的包
<dependency\>
<groupId\>org.mybatis</groupId\>
<artifactId\>mybatis</artifactId\>
<version\>${mybatis.version}</version\>
</dependency\>
<!-- Spring集成 \-->
<dependency\>
<groupId\>org.mybatis</groupId\>
<artifactId\>mybatis-spring</artifactId\>
<version\>${mybatis.spring.version}</version\>
</dependency\>
<!-- MBG \-->
<dependency\>
<groupId\>org.mybatis.generator</groupId\>
<artifactId\>mybatis-generator-core</artifactId\>
<version\>${MBG.version}</version\>
<scope\>compile</scope\>
<optional\>true</optional\>
</dependency\>
<!-- 分页 \-->
<dependency\>
<groupId\>com.github.pagehelper</groupId\>
<artifactId\>pagehelper</artifactId\>
<version\>${pagehelper.version}</version\>
</dependency\>
<!-- 通用Mapper \-->
<dependency\>
<groupId\>tk.mybatis</groupId\>
<artifactId\>mapper</artifactId\>
<version\>${mapper.version}</version\>
</dependency\>
<!-- TkMybatis 会使用到JPA的注解 \-->
<dependency\>
<groupId\>javax.persistence</groupId\>
<artifactId\>persistence-api</artifactId\>
<version\>1.0</version\>
</dependency\>
<dependency\>
<groupId\>org.postgresql</groupId\>
<artifactId\>postgresql</artifactId\>
<version\>9.3-1102-jdbc41</version\>
</dependency\>
- 配置生成器插件,指定配置文件路径,配置依赖:一个是数据库驱动,一个是通用mapper
<plugin\>
<groupId\>org.mybatis.generator</groupId\>
<artifactId\>mybatis-generator-maven-plugin</artifactId\>
<version\>${MBG.version}</version\>
<configuration\>
<configurationFile\>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile\>
<overwrite\>true</overwrite\>
<verbose\>true</verbose\>
</configuration\>
<dependencies\>
<dependency\>
<groupId\>org.postgresql</groupId\>
<artifactId\>postgresql</artifactId\>
<version\>9.3-1102-jdbc41</version\>
</dependency\>
<dependency\>
<groupId\>tk.mybatis</groupId\>
<artifactId\>mapper</artifactId\>
<version\>${mapper.version}</version\>
</dependency\>
</dependencies\>
</plugin\>
- 生成器配置文件
- 配置数据库连接
- 配置生成的model,mapper以及mapper.xml的存放路径
- 配置需要生成的表信息
注意下targetRuntime,这里采用的是MyBatis3Simple,它的默认选项是MyBatis3。如果采用通用mapper,我们在spring扫描接口时可以这样写。
<bean class=“tk.mybatis.spring.mapper.MapperScannerConfigurer”>
<property name=“sqlSessionFactoryBeanName” value=“jimSqlSessionFactory”/>
<property name=“basePackage” value=“com.jim.logstashmvc.dao.generated.mapper”/>
</bean>
如果是MyBatis3,生成的mapper.xml格式会复杂很多,我之前遇到过这样的问题:使用MyBatis3生成的mapper.xml然后错误 的配置了MapperScannerConfigurer为下面通用mapper模式,提示我的错误如下,原因可以认定是配置问题(不是某个mapper.xml中的id重复问题) ,后续再研究下非通用mapper的配置。
Caused by: java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.jim.logstashmvc.dao.generated.mapper.ProductMapper.selectByExample
at org.apache.ibatis.session.Configuration$StrictMap.put(Configuration.java:837)
at org.apache.ibatis.session.Configuration$StrictMap.put(Configuration.java:809)
上面的报错信息已经找到,原因是因为采用了MyBatis3方式生成Mapper,但同时在配置文件中错误的增加了通用Mapper的插件,它会在Mapper接口上增加一个Mapper
使用了通用Mapper之后,有个缺点就是使用Example时没有强类型的方法了,比如不能这样:
ProductExample example =new ProductExample();
ProductExample.Criteria criteria\=example.createCriteria(); if (product.getId() != null) {
criteria.andIdEqualTo(product.getId());
}
而只能这样写,字段名称需要以字符串的形式进行指定。这种方式非常适合于动态构建查询,比如:列表页的动态条件搜索
Example example = new Example(Product.class);
Example.Criteria criteria \= example.createCriteria(); if (product.getId() != null) {
criteria.andEqualTo("id", product.getId());
}
我们之前的项目为了能够使用动态条件构建,又想使用强类型的Example进行简单的查询,我们扩展了targetRuntime,让其生成的Mapper即继承自Map
public interface ImageMapper extends PartyInterface, RowBoundsMapper
List<Image> selectByConcreteExample(ImageExample example); int updateByConcreteExampleSelective(@Param("record") Image record, @Param("example") ImageExample example); int updateByConcreteExample(@Param("record") Image record, @Param("example") ImageExample example);
}
生成器的配置详细如下:
<generatorConfiguration>
<properties resource=“config.properties”/>
<context id=“jim” targetRuntime=“MyBatis3Simple” defaultModelType=“flat”>
<property name=“beginningDelimiter” value=“`“/>
<property name=“endingDelimiter” value=“`“/>
<plugin type=“${mapper.plugin}”>
<property name=“mappers” value=“${mapper.Mapper}”/>
</plugin>
<jdbcConnection driverClass=“${jdbc.driverClass}” connectionURL=“${jdbc.url}” userId=“${jdbc.username}” password=“${jdbc.password}”>
</jdbcConnection>
<javaModelGenerator targetPackage=“${targetModelPackage}” targetProject=“${targetJavaProject}”/>
<sqlMapGenerator targetPackage=“mapper” targetProject=“${targetResourcesProject}”/>
<javaClientGenerator targetPackage=“${targetMapperPackage}” targetProject=“${targetJavaProject}” type=“XMLMAPPER”>
</javaClientGenerator>
<table tableName=“product” domainObjectName=“Product”></table>
</context>
</generatorConfiguration>
- 配置maven运行参数,如下图所示即可。
- mybatis的集成,主要是配置连接池信息,插件,mapper扫描等信息。
<bean id=“jimDataSource” class=“org.apache.commons.dbcp.BasicDataSource”>
<property name=“driverClassName” value=“${jdbc.driverClass}”/>
<property name=“url” value=“${jdbc.url}”/>
<property name=“username” value=“${jdbc.username}”/>
<property name=“password” value=“${jdbc.password}”/>
<property name\="initialSize" value\="5"/>
<property name\="minIdle" value\="10"/>
<property name\="maxWait" value\="60000"/>
<property name\="timeBetweenEvictionRunsMillis" value\="60000"/>
<property name\="minEvictableIdleTimeMillis" value\="3600000"/>
<property name\="validationQuery" value\="SELECT 1"/>
<property name\="testWhileIdle" value\="true"/>
<property name\="testOnBorrow" value\="false"/>
<property name\="testOnReturn" value\="false"/>
</bean\>
<bean id\="jimSqlSessionFactory" class\="org.mybatis.spring.SqlSessionFactoryBean"\>
<property name\="dataSource" ref\="jimDataSource"/>
<property name\="mapperLocations" value\="classpath:mapper/\*.xml"/>
<property name\="typeAliasesPackage" value\="com.jim.logstashmvc.dao.generated.entity"/>
<property name\="plugins"\>
<array\>
<bean class\="com.github.pagehelper.PageHelper"\>
<property name\="properties"\>
<value\> dialect=postgresql
reasonable=true
supportMethodsArguments=true
returnPageInfo=check
params=count=countSql </value\>
</property\>
</bean\>
</array\>
</property\>
</bean\>
<bean class\="tk.mybatis.spring.mapper.MapperScannerConfigurer"\>
<property name\="sqlSessionFactoryBeanName" value\="jimSqlSessionFactory"/>
<property name\="basePackage" value\="com.jim.logstashmvc.dao.generated.mapper"/>
</bean\>
- 通用mapper的用法:
- mapper,所有生成的mapper就继承于Mapper
,默认持有通用mapper所有接口,包含CRUD常见操作 - IService,通用mapper接口的定义,我们可以根据自己的业务修改此接口
- mapper,所有生成的mapper就继承于Mapper
@Service public interface IService
T selectByKey(Object key); int save(T entity); int delete(Object key); int updateAll(T entity); int updateNotNull(T entity);
List<T> selectByExample(Object example); //TODO 其他...
}
- BaseService,通用mapper的实现类
public abstract class BaseService
@Autowired protected Mapper<T> mapper; public Mapper<T> getMapper() { return mapper;
}
@Override public T selectByKey(Object key) { return mapper.selectByPrimaryKey(key);
} public int save(T entity) { return mapper.insert(entity);
} public int delete(Object key) { return mapper.deleteByPrimaryKey(key);
} public int updateAll(T entity) { return mapper.updateByPrimaryKey(entity);
} public int updateNotNull(T entity) { return mapper.updateByPrimaryKeySelective(entity);
} public List<T> selectByExample(Object example) { return mapper.selectByExample(example);
} //TODO 其他...
}
- 具体服务类
@Service public class ProductServiceImpl extends BaseService
@Override public List
Example example = new Example(Product.class);
Example.Criteria criteria = example.createCriteria(); if(!StringUtils.isBlank(product.getName())){
criteria.andEqualTo(“name”,product.getName());
} if (product.getId() != null) {
criteria.andEqualTo(“id”, product.getId());
}
PageHelper.startPage(page, rows); return selectByExample(example);
}
}
安装postgresql并且成功远程连接,集成MBG生成mapper以及model,然后将mybatis与spring集成,最后通过通用mapper中联起来就达到了我们的目的:通过少量的代码完成大部分的工作,重复劳动交给工具完成。但通用mapper有它的优点也就有它的缺点,需要根据项目环境来平衡,个人感觉利大于弊。
本文引用:
1:http://www.mybatis.tk/
2:https://github.com/abel533/Mybatis-Spring