一般情况下,启用事务需要定义PlatformTransactionManager的实现,而TransactionTemplate适用于编程式事务(和声明式事务@Transactional区别,编程式更加灵活)。上面的配置类中只使用了两个属性,而mybatis.mapperPackages将用于MapperScannerConfigurer的加载上。添加MapperScannerRegistrarConfiguration如下:
@Configuration public class MapperScannerRegistrarConfiguration { public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, EnvironmentAware, ImportBeanDefinitionRegistrar { private Environment environment; private BeanFactory beanFactory; @Override public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } @Override public void setEnvironment(@NonNull Environment environment) { this.environment = environment; } @Override public void registerBeanDefinitions(@NonNull AnnotationMetadata importingClassMetadata, @NonNull BeanDefinitionRegistry registry) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); builder.addPropertyValue("processPropertyPlaceHolders", true); StringJoiner joiner = new StringJoiner(ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); // 这里使用了${mybatis.mapperPackages},否则会使用AutoConfigurationPackages.get(this.beanFactory)获取项目中自定义配置的包 String mapperPackages = environment.getProperty("mybatis.mapperPackages"); if (null != mapperPackages) { String[] stringArray = StringUtils.commaDelimitedListToStringArray(mapperPackages); for (String pkg : stringArray) { joiner.add(pkg); } } else { List<String> packages = AutoConfigurationPackages.get(this.beanFactory); for (String pkg : packages) { joiner.add(pkg); } } builder.addPropertyValue("basePackage", joiner.toString()); BeanWrapper beanWrapper = new BeanWrapperImpl(MapperScannerConfigurer.class); Stream.of(beanWrapper.getPropertyDescriptors()) .filter(x -> "lazyInitialization".equals(x.getName())).findAny() .ifPresent(x -> builder.addPropertyValue("lazyInitialization", "${mybatis.lazyInitialization:false}")); registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition()); } } @Configuration @Import(AutoConfiguredMapperScannerRegistrar.class) @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class}) public static class MapperScannerRegistrarNotFoundConfiguration { } }到此基本的配置Bean已经定义完毕,接着需要添加配置项。一般一个项目的MyBatis配置是相对固定的,可以直接添加在主配置文件application.properties中:
server.port=9098 spring.application.name=ch8-mybatis mybatis.configLocation=mybatis-config.xml mybatis.mapperLocations=classpath:mappings/base,classpath:mappings/ext mybatis.mapperPackages=club.throwable.ch8.repository.mapper,club.throwable.ch8.repository个人喜欢在resource/mappings目录下定义base和ext两个目录,base目录用于存在MyBatis生成器生成的XML文件,这样就能在后续添加了表字段之后直接重新生成和覆盖base目录下对应的XML文件即可。同理,在项目的源码包下建repository/mapper,然后Mapper类直接存放在repository/mapper目录,DAO类存放在repository目录,MyBatis生成器生成的Mapper类可以直接覆盖repository/mapper目录中对应的类。
resources目录下添加一个MyBatis的全局配置文件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> <settings> <!--下划线转驼峰--> <setting value="true"/> <!--未知列映射忽略--> <setting value="NONE"/> </settings> </configuration>项目目前的基本结构如下:
使用Mybatis为了简单起见,这里使用h2内存数据库进行演示。添加h2的依赖:
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>1.4.200</version> </dependency>resources目录下添加一个schema.sql和data.sql:
// resources/schema.sql drop table if exists customer; create table customer ( id bigint generated by default as identity, customer_name varchar(32), age int, create_time timestamp default current_timestamp, edit_time timestamp default current_timestamp, primary key (id) ); // resources/data.sql INSERT INTO customer(customer_name,age) VALUES ('doge', 22); INSERT INTO customer(customer_name,age) VALUES ('throwable', 23);添加对应的实体类club.throwable.ch8.entity.Customer:
@Data public class Customer { private Long id; private String customerName; private Integer age; private LocalDateTime createTime; private LocalDateTime editTime; }