J2EE
開(kāi)發(fā)界中一個(gè)永遠(yuǎn)避免不了的爭(zhēng)論就是Hibernate
與Mybatis
哪個(gè)好弊知。雖然我自己傾向Hibernate
握牧,但這兩種ORM
框架我也都沒(méi)有在比較大型的場(chǎng)景上使用過(guò)容诬,沒(méi)有資格做評(píng)價(jià)。
最近公司有一個(gè)項(xiàng)目沿腰,主程讓我用Spring
與Mybatis
搭建服務(wù)端框架放案,這里就做一下簡(jiǎn)單的學(xué)習(xí)記錄。
Java Config方式的Mybatis啟動(dòng)配置
首先在maven
中加上Mybatis
與mybatis-spring
的依賴:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
前一篇中提到矫俺,公司推薦Spring
使用Java Config
的方式進(jìn)行配置,所以Mybatis
也不例外掸冤。
先看一段網(wǎng)上找到比較常見(jiàn)的xml方式配置:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--指定實(shí)體類映射文件厘托,可以指定同時(shí)指定某一包以及子包下面的所有配置文件 -->
<property name="mapperLocations" value="classpath*:com/nd/mathlearning/server/*/dao/mapper/*.xml"/>
<!--mybatis全局配置文件 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
配置的核心是sqlSessionFactory
,將dataSource
數(shù)據(jù)源注入就完成了Mybatis
會(huì)話工廠的實(shí)例化了稿湿。
接著把這段配置翻譯成Java config
版本:
@Configuration
@PropertySource("classpath:druid-config.properties")
public class JdbcConfig {
@Value("${druid.driverClassName}")
private String driverClassName;
@Value("${druid.url}")
private String url;
@Value("${druid.user}")
private String username;
@Value("${druid.password}")
private String password;
@Value("${druid.maxActive}")
private int maxActive;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driverClassName);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
ds.setMaxActive(maxActive);
ds.setMinIdle(0);
return ds;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactory() throws IOException {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//加載匹配到的xml映射配置
Resource[] resources = resolver.getResources("classpath*:com/nd/mathlearning/server/*/dao/mapper/*.xml");
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource());
bean.setMapperLocations(resources);
//加載Mybatis配置
bean.setConfigLocation(resolver.getResource("classpath:mybatis/mybatis-config.xml"));
return bean;
}
@Bean
public SqlSessionTemplate sqlSessionTemplate() throws Exception {
SqlSessionTemplate bean = new SqlSessionTemplate(sqlSessionFactory().getObject());
return bean;
}
}
-
@Configuration
表明此類用作Spring配置
-
@PropertySource
說(shuō)明讀取哪個(gè)配置文件 -
@Value
將properties
中的配置項(xiàng)注入進(jìn)變量 -
@Bean
注解的方法表明實(shí)例化對(duì)象铅匹。 -
ResourcePatternResolver
是用來(lái)加載工程配置文件。
Mybatis的xml映射文件
與Hibernate
類似饺藤,Mybatis
需要寫xml
配置來(lái)實(shí)現(xiàn)Java
類與數(shù)據(jù)庫(kù)表之間的映射關(guān)系包斑,更多的流礁,Mybatis
框架執(zhí)行的所有sql
也都配置在xml
中。
來(lái)看一段完整的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.nd.mathlearning.server.personal.dao.UcUseridMapMapper" >
<resultMap id="BaseResultMap" type="com.nd.mathlearning.server.personal.dto.UcUseridMapEntity" >
<id column="uc_user_id" property="ucUserId" jdbcType="BIGINT" />
<result column="user_id" property="userId" jdbcType="BIGINT" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
</resultMap>
<sql id="Base_Column_List" >
uc_user_id, user_id, user_name
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
select
<include refid="Base_Column_List" />
from uc_userid_map
where uc_user_id = #{ucUserId,jdbcType=BIGINT}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >
delete from uc_userid_map
where uc_user_id = #{ucUserId,jdbcType=BIGINT}
</delete>
<insert id="insert" parameterType="com.nd.mathlearning.server.personal.dto.UcUseridMapEntity" >
insert into uc_userid_map (uc_user_id, user_id, user_name
)
values (#{ucUserId,jdbcType=BIGINT}, #{userId,jdbcType=BIGINT}, #{userName,jdbcType=VARCHAR}
)
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.nd.mathlearning.server.personal.dto.UcUseridMapEntity" >
update uc_userid_map
<set >
<if test="userId != null" >
user_id = #{userId,jdbcType=BIGINT},
</if>
<if test="userName != null" >
user_name = #{userName,jdbcType=VARCHAR},
</if>
</set>
where uc_user_id = #{ucUserId,jdbcType=BIGINT}
</update>
</mapper>
- 根節(jié)點(diǎn)
mapper
中的namespace
聲明了此配置的唯一編號(hào)罗丰,在此后的java
的api
調(diào)用就需要用到此屬性神帅。 -
resultMap
定義表到java
實(shí)體類之間的字段映射關(guān)系 -
column
是表字段 -
property
是類屬性 -
jdbcType
是表字段類型。 -
sql
節(jié)點(diǎn)在這里定義了一個(gè)sql
查詢片段萌抵,使用include
語(yǔ)法拼接找御,用于簡(jiǎn)化配置。 -
select
绍填,insert
霎桅,update
,delete
節(jié)點(diǎn)定義四種sql
操作的方法讨永。id
定義方法的標(biāo)識(shí)滔驶; -
parameterType
說(shuō)明方法的參數(shù)類型,可以是javabean
卿闹,但一個(gè)方法只能有一個(gè)輸入?yún)?shù)揭糕。
更詳細(xì)的mapper
配置說(shuō)明參考官網(wǎng):
mapper與實(shí)體生成工具
既然Mybatis
所有的邏輯操作都是配置在xml
中,那就把原來(lái)在java
中的sql
開(kāi)發(fā)工作轉(zhuǎn)換到了xml
上比原。
與Hibernate
一樣插佛,Mybatis
提供了一個(gè)簡(jiǎn)易的逆向工程工具,幫助我們根據(jù)已有數(shù)據(jù)表生成對(duì)應(yīng)的javabean
和基本操作xml
配置量窘。
在maven
中增加生成器依賴:
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
編寫生成配置xml
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
<!-- classPathEntry:數(shù)據(jù)庫(kù)的JDBC驅(qū)動(dòng) -->
<classPathEntry location="F:\mylib\mysql-connector-java-5.1.30.jar" />
<!--生成映射的類型雇寇,也可以生成ibatis的。具體參看mybatis-generator -->
<context id="DB2Tables3" targetRuntime="MyBatis3">
<plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin"></plugin>
<plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>
<!-- 去除自動(dòng)生成的注釋 -->
<commentGenerator>
<property name="suppressDate" value="true" />
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!-- 數(shù)據(jù)庫(kù)配置 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://172.24.133.201:3306/mylearning" userId="user_account"
password="user_account">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!--以下三個(gè)標(biāo)簽主要解析targetPackage和targetProject蚌铜。其它的具體參看mybatis-generator -->
<!-- targetProject:自動(dòng)生成代碼的位置 -->
<javaModelGenerator targetPackage="com.nd.mathlearning.server.microclass.dto" targetProject="src/main/java/">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
</javaModelGenerator>
<sqlMapGenerator targetPackage="com.nd.mathlearning.server.microclass.dao" targetProject="src/main/java/">
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!-- 要生成的表配置 -->
<table tableName="mc_note" domainObjectName="McNoteEntity" enableCountByExample="false" enableUpdateByExample="false"
enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
</context>
</generatorConfiguration>
有了生成配置xml
后就可以調(diào)用api
生成實(shí)體javabean
锨侯,dao
和mapper
:
public class MyBatisGenerator {
public static void main(String args[]){
String config ="";
try {
config = MyBatisGenerator.class.getResource("generator.xml").toURI().getPath();
} catch (URISyntaxException e) {
e.printStackTrace();
}
String[] arg = { "-configfile", config, "-overwrite" };
ShellRunner.main(arg);
}
}
參考文章:
與Spring整合
在j2ee
的各種開(kāi)源框架中囚痴,我們最關(guān)心的可能就是怎么與Spring
做整合。
數(shù)據(jù)映射器 MapperFactoryBean
Mybatis
提供了一種簡(jiǎn)易的整合方式审葬,使用class
的方式定義mapper
深滚,而不需要配置xml
。
例如定義一個(gè)interface
的mapper
:
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{userId}")
User getUser(@Param("userId") long id);
}
然后在spring
中定義:
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.xxt.ibatis.dbcp.dao.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
Spring
容器中就產(chǎn)生了userMapper
實(shí)例可以來(lái)執(zhí)行我們想要的數(shù)據(jù)操作涣觉。這種方式有點(diǎn)類似spring data
中CrudRepository
的@Query
用法痴荐。
抽象類SqlSessionDaoSupport的整合方式
從前面的啟動(dòng)配置我們知道了,Mybatis
的api
入口是sqlSessionFactory
官册。Mybatis
提供SqlSessionDaoSupport
抽象類來(lái)方便獲取sqlSession
生兆。
先看一個(gè)UserDao的實(shí)現(xiàn):
public class UserDao extends SqlSessionDaoSupport{
@Autowired
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
super.setSqlSessionTemplate(sqlSessionTemplate);
}
public User getUserById(User user) {
return (User) getSqlSession().selectOne("com.xxt.ibatis.dbcp.domain.User.getUser", user);
}
}
繼承SqlSessionDaoSupport
可以獲得getSqlSession
方法來(lái)得到sqlSession
。然后通過(guò)sqlSession
的api
最終調(diào)用到mapper
里配置的sql
程序膝宁。
sqlSession幾個(gè)常用的api:
<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)
第一個(gè)參數(shù)表示mapper中方法的唯一標(biāo)識(shí)鸦难,結(jié)構(gòu)為:mapper標(biāo)識(shí) + . + 方法標(biāo)識(shí)根吁。
mybatis-spring 1.2版本中SqlSessionDaoSupport的變化
首先看1.2版本中SqlSessionDaoSupport
的注釋信息:
/**
* Convenient super class for MyBatis SqlSession data access objects.
* It gives you access to the template which can then be used to execute SQL methods.
* <p>
* This class needs a SqlSessionTemplate or a SqlSessionFactory.
* If both are set the SqlSessionFactory will be ignored.
* <p>
* {code Autowired} was removed from setSqlSessionTemplate and setSqlSessionFactory
* in version 1.2.0.
*
* @author Putthibong Boonbong
*
* @see #setSqlSessionFactory
* @see #setSqlSessionTemplate
* @see SqlSessionTemplate
* @version $Id$
*/
之前版本中setSqlSessionTemplate
和setSqlSessionFactory
是Autowired
,1.2之后需要我們手動(dòng)注入合蔽。
這個(gè)改動(dòng)應(yīng)該是為了支持一個(gè)項(xiàng)目中建立多數(shù)據(jù)源的場(chǎng)景击敌,我們可以用SqlSessionDaoSupport
創(chuàng)建多個(gè)DAO層基類,選擇不同的數(shù)據(jù)源注入辈末。
參考文章:
Mybatis插件配置
Mybatis
提供了插件機(jī)制實(shí)現(xiàn)了功能擴(kuò)展
分頁(yè)插件PageHelper
數(shù)據(jù)庫(kù)列表查詢少不了分頁(yè)功能愚争,怎么在代碼級(jí)別上簡(jiǎn)單有效地處理分頁(yè)邏輯總是一大挑戰(zhàn)。
實(shí)現(xiàn)分頁(yè)功能關(guān)鍵是根據(jù) 兩個(gè)參數(shù) 得到 兩個(gè)數(shù)據(jù):
- 兩個(gè)參數(shù):數(shù)據(jù)偏移量 和 頁(yè)面大小(或者通過(guò) 當(dāng)前頁(yè)碼 和 頁(yè)面大小 進(jìn)行轉(zhuǎn)換)
- 兩個(gè)數(shù)據(jù):當(dāng)前頁(yè)面的列表數(shù)據(jù) 和 總記錄數(shù)
在sql
層面上講挤聘,需要兩次查詢:
- 根據(jù)查詢條件用
limit
參數(shù)(在oracle
用rownum
)得到當(dāng)前請(qǐng)求頁(yè)面數(shù)據(jù)轰枝。 - 用相同的條件
count(*)
查詢數(shù)據(jù)庫(kù)中存在的總數(shù)。
回到Mybatis
组去,我們可以利用它的插件機(jī)制實(shí)現(xiàn)分頁(yè)功能鞍陨。
首先加上PageHelper
的maven
配置:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.1</version>
</dependency>
在初始化sqlSessionFactory
時(shí)加上插件配置:
@Bean
public SqlSessionFactoryBean sqlSessionFactory() throws IOException {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath*:com/nd/mathlearning/server/*/dao/mapper/*.xml");
Interceptor[] plugings = new Interceptor[1];
PageHelper pageHelper = new PageHelper();//mybatis分頁(yè)插件
Properties p = new Properties();//插件屬性配置
p.put("dialect", "mysql"); //數(shù)據(jù)庫(kù)言
p.put("reasonable", "true");//參數(shù)合理化,如果pageNum<1會(huì)查詢第一頁(yè)从隆,如果pageNum>pages會(huì)查詢最后一頁(yè)
p.put("offsetAsPageNum", "trsue"); //將RowBounds第一個(gè)參數(shù)offset當(dāng)成pageNum頁(yè)碼使用
pageHelper.setProperties(p);
plugings[0] = pageHelper;
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource());
bean.setMapperLocations(resources);
bean.setPlugins(plugings); //插件注入到sqlSessionFactory
bean.setConfigLocation(resolver.getResource("classpath:mybatis/mybatis-config.xml"));
return bean;
}
其中屬性配置詳細(xì)信息參考項(xiàng)目主頁(yè)诚撵。
在調(diào)用Mybatis
的api
時(shí)增加RowBounds
參數(shù)實(shí)現(xiàn)分頁(yè):
List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(1, 10));
項(xiàng)目主頁(yè):