1. 项目简介
本篇文章将会介绍如何将Spring Boot、MyBatis、Atomikos、MySQL这几个框架和数据库组合起来构建一个分布式事务应用。本项目实现了一个简单的用户注册功能,其中包括了数据库的读写操作。在本项目中,我们使用了Spring Boot作为应用框架,MyBatis作为ORM框架,Atomikos作为分布式事务管理器,MySQL作为存储数据库。
2. 准备工作
2.1 创建Spring Boot项目
首先,我们需要创建一个Spring Boot项目。可以使用IDE工具(如IDEA或Eclipse)创建一个Spring Boot项目。也可以使用Spring Initializr创建一个空的Spring Boot项目。这里我们使用Spring Initializr创建一个Spring Boot项目,并添加Web和MyBatis的依赖。
在pom.xml文件中添加以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
2.2 创建MySQL数据库
接下来,我们需要在本地创建一个MySQL数据库。可以使用命令行工具或使用第三方工具(如Navicat或MySQL Workbench等)创建一个MySQL数据库。本项目需要创建一个名为“test”的数据库,并在该数据库中创建一个名为“user”的表,表结构如下:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
3. 配置MyBatis
在完成上述准备工作后,接下来我们需要配置MyBatis。在Spring Boot项目中,MyBatis自动配置是开启的,我们只需要在application.properties
文件中进行相关配置即可。在本项目中,我们使用了MySQL数据库作为存储数据库,所以需要进行如下配置:
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
mybatis.config-location=classpath:mybatis-config.xml
mybatis.mapper-locations=classpath:mapper/*.xml
其中,mybatis-config.xml
文件用于配置MyBatis,可以在其中添加一些自定义的配置,比如类型别名、插件等。在本项目中,mybatis-config.xml
文件内容如下:
<configuration>
<typeAliases>
<typeAlias type="com.example.demo.entity.User" alias="User"/>
</typeAliases>
</configuration>
在mapper
目录中,我们需要为User
实体创建相应的Mapper文件,并编写SQL语句。在本项目中,我们创建了一个名为UserMapper.xml
的Mapper文件,内容如下:
<mapper namespace="com.example.demo.mapper.UserMapper">
<resultMap id="BaseResultMap" type="User">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="age" property="age" jdbcType="INTEGER"/>
</resultMap>
<select id="selectAll" resultMap="BaseResultMap">
select * from user
</select>
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into user (name, age)
values (#{name}, #{age})
</insert>
</mapper>
4. 配置Atomikos
接下来,我们需要配置Atomikos。Atomikos是一个Java事务管理框架,可以帮助我们管理分布式事务。在本项目中,我们需要将MySQL数据库配置为一个XA数据源,然后再将它注册到Atomikos中。
4.1 添加Atomikos的依赖
在pom.xml文件中添加Atomikos的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
<version>2.5.0</version>
</dependency>
上面的依赖包含了Spring框架的JTA和Atomikos的相关类。
4.2 配置数据库为XA数据源
在application.properties
文件中添加以下内容,将MySQL数据库配置为XA数据源:
spring.datasource.unique-resource-name=myDataSource
spring.datasource.xa.dataSourceClassName=com.mysql.cj.jdbc.MysqlXADataSource
spring.datasource.xa.properties.user=root
spring.datasource.xa.properties.password=123456
spring.datasource.xa.properties.URL=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.xa.properties.cachePrepStmts=true
spring.datasource.xa.properties.cachePrepStmtsSize=250
spring.datasource.xa.properties.prepStmtCacheSqlLimit=2048
spring.datasource.xa.properties.useServerPrepStmts=true
4.3 写Atomikos的配置文件
接下来,我们需要为Atomikos创建一个配置文件atomikos.properties
,并配置JTA的相关参数。在项目的src/main/resources
目录下创建一个文件夹config
,并在该目录下创建atomikos.properties
文件。内容如下:
com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
com.atomikos.icatch.log_base_dir=./XATransactionLogs
com.atomikos.icatch.automatic_resource_registration=true
java.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory
java.naming.provider.url=rmi://127.0.0.1:1099/
com.atomikos.icatch.max_timeout=60
上面的配置文件中,com.atomikos.icatch.service
参数是必须的,表示使用Atomikos的事务管理器;com.atomikos.icatch.log_base_dir
参数表示事务日志的存储路径;com.atomikos.icatch.automatic_resource_registration
参数表示注册分布式资源时,是否自动启用重试机制;java.naming.factory.initial
和java.naming.provider.url
两个参数为JNDI的引用,用于指定Atomikos的JNDI服务地址和端口号;com.atomikos.icatch.max_timeout
参数表示事务最大超时时间,单位为秒。
4.4 配置JTA
最后,在application.properties
文件中添加以下内容,配置使用JTA分布式事务管理器:
spring.datasource.type=com.atomikos.jdbc.AtomikosDataSourceBean
spring.jta.atomikos.datasource.unique-resource-name=myDataSource
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=3000
mybatis.configuration.cache-enabled=false
mybatis.executor-type=batch
上面的配置文件中,spring.datasource.type
参数表示使用AtomikosDataSourceBean作为数据源,从而使用Atomikos管理分布式事务;spring.jta.atomikos.datasource.unique-resource-name
参数表示JTA中的数据源名称,且必须与spring.datasource.unique-resource-name
参数保持一致。
5. 编写Java代码
现在,我们已经完成了Spring Boot、MyBatis、Atomikos、MySQL的配置,接下来就是编写Java代码了。
5.1 创建实体类
首先,我们需要创建一个实体类User
,用于映射user
表中的记录。实体类代码如下:
public class User {
private Integer id;
private String name;
private Integer age;
// getter and setter methods
}
5.2 创建Mapper接口
接下来,我们需要创建一个Mapper接口UserMapper
,用于将Java对象与SQL语句进行映射。Mapper接口代码如下:
@Mapper
public interface UserMapper {
@Select("select * from user")
List<User> selectAll();
@Insert("insert into user (name, age) values (#{name}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
Integer insert(User user);
}
在上面的UserMapper
接口中,我们使用@Mapper
注解表示该接口为Mapper接口,然后定义了两个方法selectAll
和insert
,分别对应于user
表中的查询和插入操作。由于插入操作需要返回自增主键的值,因此使用了@Options
注解。
5.3 创建Service实现类
接下来,我们需要创建一个Service实现类UserServiceImpl
,用于实现业务逻辑。在该类中,我们需要将业务逻辑包装在一个分布式事务中。Service实现类代码如下:
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> selectAll() {
return userMapper.selectAll();
}
@Override
public Integer insert(User user) {
return userMapper.insert(user);
}
}
上面的代码中,我们首先使用@Slf4j
注解创建一个log
对象,用于输出日志。然后,使用@Service
注解表示该类为Service实现类,使用@Transactional
注解表示将该类中所有方法都包装在一个分布式事务中处理。最后,我们使用@Autowired
注解自动注入UserMapper
,并实现了selectAll
和insert
两个方法。
5.4 创建Controller类
最后,我们需要创建一个Controller类UserController
,用于接收外部请求并调用Service中的方法。Controller类代码如下:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/selectAll")
public List<User> selectAll() {
return userService.selectAll();
}
@PostMapping("/insert")
public Integer insert(@RequestBody User user) {
return userService.insert(user);
}
}
上面的代码中,我们使用@RestController
注解表示该类为Controller类,并使用@RequestMapping
注解设置请求路径。然后,使用@Autowired
注解自动注入UserService
,并实现了查询和插入操作的接口方法。
6. 测试
现在,我们已经完成了各种配置和代码的编写工作,接下来可以启动Spring Boot应用,测试它是否能正常工作。可以使用Postman或其他API工具,向接口/user/selectAll
发送GET请求,查询数据库中已经有的用户信息。也可以使用接口/user/insert
创建新用户信息,将新用户信息插入数据库。如果一切正常,我们就成功地创建了一个使用Spring Boot+MyBatis+Atomikos+MySQL的分布式事务应用。