基于Spring Boot自定义Mybatis配置实例
MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。随着2013年开源以来,目前业内使用的也越来越多。下面通过一个实例来说明一下怎么去使用它,怎么体现出它的优势所在:
由于我是基于Spring Boot的来说明mybatis的使用,所以首先我们需要配置好mybatis。
依赖包
<!--依赖-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1208</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.20</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
<version>1.4.192</version>
</dependency>
配置文件准备
在 src/main/resources/下面添加如下properties文件:
application.properties
spring.profiles.active=@profiles.active@ jdbc.url=${jdbc.url} jdbc.username= ${jdbc.username} jdbc.password= ${jdbc.password} jdbc.driver=${jdbc.driver} jdbc.poolMaximumActiveConnections=${jdbc.poolMaximumActiveConnections} jdbc.poolMaximumIdleConnections=${jdbc.poolMaximumIdleConnections}
application-develop.properties(测试用)
jdbc.url=jdbc:h2:mem:demo-db;MODE=PostgreSQL;INIT=RUNSCRIPT FROM './src/test/resources/sql/demo.sql' jdbc.username= sa jdbc.password= sa jdbc.driver= org.h2.Driver jdbc.poolMaximumActiveConnections=20 jdbc.poolMaximumIdleConnections=0
application-production.properties(生产用)
jdbc.url=jdbc:postgresql://192.168.100.117:5432/db_demo?characterEncoding#UTF-8 jdbc.username= postgres jdbc.password= postgres jdbc.driver=org.postgresql.Driver jdbc.poolMaximumActiveConnections=30 jdbc.poolMaximumIdleConnections=0
Mybatis自定义配置文件实现
在src/main/java/com.jmust.service.demo下创建”MybatisConfiguration.java”文件
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = {"com.jmust.service.demo.resource.mapper"})
public class MybatisConfiguration {
@Autowired
private Environment env;
@Autowired
private DataSource pooledDataSource;
private static Log logger = LogFactory.getLog(MybatisConfiguration.class);
@PostConstruct
@Bean
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setPassword(env.getProperty("jdbc.password"));
druidDataSource.setUsername(env.getProperty("jdbc.username"));
druidDataSource.setUrl(env.getProperty("jdbc.url"));
druidDataSource.setDriverClassName(env.getProperty("jdbc.driver"));
druidDataSource.setMaxActive(Integer.parseInt(env.getProperty("jdbc.poolMaximumActiveConnections")));
return druidDataSource;
}
@Bean
public SqlSessionFactory sqlSessionFactory() {
try {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(pooledDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapping/*.xml"));
return sessionFactory.getObject();
} catch (Exception e) {
logger.error("not install sessionFactory", e);
throw new RuntimeException("not install sessionFactory");
}
}
@Bean
public DataSourceTransactionManager transaction() {
return new DataSourceTransactionManager(pooledDataSource);
}
}
Mybatis代码生成
- 1、生成xxxMapper.java接口文件(src/main/com.jmust.service.demo.resource.mapper),该文件主要作用是映射到xxxMapper.xml文件中的操作标签的(比如insert对应xml文件中的
) import com.jmust.service.demo.resource.entity.Demo; import org.springframework.stereotype.Repository; import java.util.Date; @Repository public interface DemoMapper { Demo select(long customerId); boolean insert(Demo demoPojo); boolean update(Demo demoPojo); }
2、生成xxxMapper.xml文件(src/main/resources/mapping/),该文件的主要作用就是操作数据(插入、更改、删除……)语句的维护及管理
<?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.jmust.service.demo.resource.mapper.DemoMapper"> <resultMap id="demoPojo" type="com.jmust.service.demo.resource.entity.Demo"> <result column="customer_id" property="customerId"/> <result column="total_times" property="totalTimes"/> <result column="continue_days" property="continueDays"/> <result column="last_time" property="lastTime"/> </resultMap>
<select id="select" resultMap="demoPojo" parameterType="long">
SELECT * FROM demo
WHERE customer_id = #{customerId}
</select>
<insert id="insert" parameterType="com.jmust.service.demo.resource.entity.Demo">
insert into demo(customer_id,total_times,continue_days,last_time)
values
(#{customerId},1,#{continueDays},#{lastTime},#{awardType})
</insert>
<update id="update" parameterType="com.jmust.service.demo.resource.entity.Demo">
update demo
<set>
<if test="continueDays != null">
continue_days = #{continueDays},
</if>
<if test="awardType != null">
award_type = #{awardType},
</if>
<if test="lastTime != null">
last_time = #{lastTime}
</if>
</set>
where customer_id = #{customerId}
</update>
</mapper>
3、自定义接口类(DemoResources)src/main/com.jmust.service.demo.resource,定义操作契约
import com.jmust.service.demo.resource.entity.Demo; import java.util.Date; public interface DemoResources { Demo queryDemo(long customerId); void update(Demo demoinPojo); void insert(Demo demoPojo); }
4、实现接口类,业务逻辑包含在内(src/main/com.jmust.service.demo.resource)
import com.jmust.contract.ExtendedStatusRuntimeException; import com.jmust.contract.ResourceUnavailableException; import com.jmust.service.demo.DemoStatus; import com.jmust.service.demo.resource.entity.Demo; import com.jmust.service.demo.resource.mapper.DemoMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Component; import java.util.Date; @Component public class DemoResourcesImpl implements DemoResources{ @Autowired private DemoMapper demoMapper; @Override public Demo queryDemo(long customerId) { try { return demoMapper.select(customerId); }catch (Exception e){ throw new ResourceUnavailableException("Database fail select Demo",e); } } @Override public void update(Demo demoPojo) { try { if(!demoMapper.update(demoPojo)){ throw new ExtendedStatusRuntimeException(101, "Demo process fail ,because Demo update fail"); } }catch (Exception e){ throw new ResourceUnavailableException("Database fail update demoPojo",e); } } @Override public void insert(Demo demo) { try { if(!demoMapper.insert(demo)){ throw new ExtendedStatusRuntimeException(102, "demo process fail ,because demo insert fail"); } }catch (DuplicateKeyException e){ if(!DemoMapper.update(demo)){ throw new ExtendedStatusRuntimeException(102, "demo process fail " + ",because demo update fail"); } }catch (Exception e){ throw new ResourceUnavailableException("Database fail insert demoPojo ",e); } } }
项目测试
import com.jmust.server.profile.ProfileDevelop;
import com.jmust.server.profile.ProfileTest;
import com.jmust.service.demo.DemoConstants;
import com.jmust.service.demo.MybatisConfiguration;
import com.jmust.service.demo.resource.entity.Demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.sql.Timestamp;
import java.util.Date;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@ProfileTest
@ProfileDevelop
@ContextConfiguration(classes = {MybatisConfiguration.class, DemoResourcesImpl.class})
@TestPropertySource(value = "classpath:application.properties")
public class DemoPojoResourcesTest extends AbstractTestNGSpringContextTests {
private Long concurrent = System.currentTimeMillis();
private int customerId = 11;
@Autowired
private DemoResources cm;
@BeforeClass
public void insert() {
Demo demoPojo = new Demo();
demoPojo.setCustomerId(customerId);
demoPojo.setCreateTime(new Timestamp(concurrent));
demoPojo.setAwardTypeEnum("");
demoPojo.setTotalTimes(0);
cm.insert(demoPojo);
}
@Test
public void queryDemo() {
Demo demoPojo = cm.queryDemo(customerId);
assertThat(demoPojo.getCustomerId()).isEqualTo(customerId);
assertThat(demoPojo.getCreateTime()).isEqualTo(new Timestamp(concurrent));
assertThat(demoPojo.getTotalTimes()).isEqualTo(1);
}
}