- 后端:引入分布式事务框架 seata 框架。
- 后端:目前订单提交时,如果发生异常,会回滚优惠劵的使用。
This commit is contained in:
@@ -1,9 +1,20 @@
|
||||
package cn.iocoder.mall.order.biz.config;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import io.seata.rm.datasource.DataSourceProxy;
|
||||
import io.seata.spring.annotation.GlobalTransactionScanner;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@MapperScan("cn.iocoder.mall.order.biz.dao") // 扫描对应的 Mapper 接口
|
||||
@EnableTransactionManagement(proxyTargetClass = true) // 启动事务管理。为什么使用 proxyTargetClass 参数,参见 https://blog.csdn.net/huang_550/article/details/76492600
|
||||
@@ -11,4 +22,54 @@ public class DatabaseConfiguration {
|
||||
|
||||
// 数据源,使用 HikariCP
|
||||
|
||||
}
|
||||
@Value("${spring.application.name}")
|
||||
private String applicationId;
|
||||
|
||||
@Autowired
|
||||
private DataSourceProperties dataSourceProperties;
|
||||
|
||||
@Bean
|
||||
// @Primary
|
||||
public DruidDataSource druidDataSource(){
|
||||
DruidDataSource druidDataSource = new DruidDataSource();
|
||||
druidDataSource.setUrl(dataSourceProperties.getUrl());
|
||||
druidDataSource.setUsername(dataSourceProperties.getUsername());
|
||||
druidDataSource.setPassword(dataSourceProperties.getPassword());
|
||||
druidDataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
|
||||
druidDataSource.setInitialSize(0);
|
||||
druidDataSource.setMaxActive(180);
|
||||
druidDataSource.setMaxWait(60000);
|
||||
druidDataSource.setMinIdle(0);
|
||||
druidDataSource.setValidationQuery("Select 1 from DUAL");
|
||||
druidDataSource.setTestOnBorrow(false);
|
||||
druidDataSource.setTestOnReturn(false);
|
||||
druidDataSource.setTestWhileIdle(true);
|
||||
druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
|
||||
druidDataSource.setMinEvictableIdleTimeMillis(25200000);
|
||||
druidDataSource.setRemoveAbandoned(true);
|
||||
druidDataSource.setRemoveAbandonedTimeout(1800);
|
||||
druidDataSource.setLogAbandoned(true);
|
||||
return druidDataSource;
|
||||
}
|
||||
|
||||
@ConfigurationProperties(prefix = "spring.datasource")
|
||||
@Primary
|
||||
@Bean("dataSource")
|
||||
// @Bean
|
||||
public DataSource dataSource(DruidDataSource dataSource) {
|
||||
return new DataSourceProxy(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册一个StatViewServlet
|
||||
*
|
||||
* @return global transaction scanner
|
||||
*/
|
||||
@Bean
|
||||
public GlobalTransactionScanner globalTransactionScanner() {
|
||||
return new GlobalTransactionScanner(applicationId, "my_test_tx_group");
|
||||
// TODO 芋艿,txServiceGroup 后续要编辑下
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package cn.iocoder.mall.order.biz.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class SeataConfiguration {
|
||||
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package cn.iocoder.mall.order.biz.dao;
|
||||
|
||||
import cn.iocoder.mall.order.api.dto.OrderQueryDTO;
|
||||
import cn.iocoder.mall.order.biz.dataobject.OrderDO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@@ -14,14 +15,7 @@ import java.util.List;
|
||||
* @time 2019-03-16 15:09
|
||||
*/
|
||||
@Repository
|
||||
public interface OrderMapper {
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*
|
||||
* @param orderDO
|
||||
*/
|
||||
void insert(OrderDO orderDO);
|
||||
public interface OrderMapper extends BaseMapper<OrderDO> {
|
||||
|
||||
/**
|
||||
* 更新 - 根据 id 更新
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.iocoder.mall.order.biz.dataobject;
|
||||
|
||||
import cn.iocoder.common.framework.dataobject.DeletableDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@@ -14,6 +15,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName(value = "orders")
|
||||
public class OrderDO extends DeletableDO {
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,6 +21,7 @@ import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO;
|
||||
import cn.iocoder.mall.promotion.api.CouponService;
|
||||
import cn.iocoder.mall.user.api.UserAddressService;
|
||||
import cn.iocoder.mall.user.api.bo.UserAddressBO;
|
||||
import io.seata.spring.annotation.GlobalTransactional;
|
||||
import org.apache.dubbo.config.annotation.Reference;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -210,6 +211,7 @@ public class OrderServiceImpl implements OrderService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@GlobalTransactional
|
||||
@Transactional // TODO 芋艿,先不考虑分布式事务的问题
|
||||
public CommonResult<OrderCreateBO> createOrder(OrderCreateDTO orderCreateDTO) {
|
||||
Integer userId = orderCreateDTO.getUserId();
|
||||
@@ -284,8 +286,8 @@ public class OrderServiceImpl implements OrderService {
|
||||
.setHasReturnExchange(OrderHasReturnExchangeEnum.NO.getValue())
|
||||
.setRemark(Optional.ofNullable(orderCreateDTO.getRemark()).orElse(""));
|
||||
orderDO.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
|
||||
orderDO.setCreateTime(new Date());
|
||||
orderDO.setUpdateTime(null);
|
||||
// orderDO.setCreateTime(new Date());
|
||||
// orderDO.setUpdateTime(null);
|
||||
orderMapper.insert(orderDO);
|
||||
|
||||
// 收件人信息
|
||||
@@ -321,6 +323,10 @@ public class OrderServiceImpl implements OrderService {
|
||||
// 一次性插入
|
||||
orderItemMapper.insert(orderItemDOList);
|
||||
|
||||
if (true) {
|
||||
throw new RuntimeException("测试 seata 事务回滚");
|
||||
}
|
||||
|
||||
// 创建预订单
|
||||
createPayTransaction(orderDO, orderItemDOList, orderCreateDTO.getIp());
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ dubbo:
|
||||
CartService:
|
||||
version: 1.0.0
|
||||
consumer:
|
||||
timeout: 120000 # 设置长一点,方便调试代码
|
||||
ProductSpuService:
|
||||
version: 1.0.0
|
||||
PromotionActivityService:
|
||||
|
||||
@@ -9,26 +9,6 @@
|
||||
status, remark, create_time, update_time, `deleted`
|
||||
</sql>
|
||||
|
||||
<!--
|
||||
插入数据
|
||||
-->
|
||||
<insert id="insert" parameterType="OrderDO" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
|
||||
INSERT INTO `order` (
|
||||
user_id, order_no, buy_price, discount_price, logistics_price, present_price, pay_amount,
|
||||
payment_time, delivery_time, receiver_time, closing_time,
|
||||
has_return_exchange,
|
||||
status, remark, create_time, update_time, `deleted`
|
||||
) VALUES (
|
||||
#{userId}, #{orderNo}, #{buyPrice}, #{discountPrice}, #{logisticsPrice}, #{presentPrice}, #{payAmount},
|
||||
#{paymentTime}, #{deliveryTime}, #{receiverTime}, #{closingTime},
|
||||
#{hasReturnExchange},
|
||||
#{status}, #{remark}, #{createTime}, #{updateTime}, #{deleted}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!--
|
||||
更新 - 可更新的字段
|
||||
-->
|
||||
<sql id="updateFieldSql" >
|
||||
<set>
|
||||
<if test="orderNo != null">
|
||||
@@ -86,9 +66,6 @@
|
||||
</set>
|
||||
</sql>
|
||||
|
||||
<!--
|
||||
更新 - 根据 id 更新
|
||||
-->
|
||||
<update id="updateById" parameterType="OrderDO">
|
||||
UPDATE `order`
|
||||
<include refid="updateFieldSql" />
|
||||
@@ -112,9 +89,6 @@
|
||||
AND status = #{status}
|
||||
</update>
|
||||
|
||||
<!--
|
||||
查询 - 根据id 查询
|
||||
-->
|
||||
<select id="selectById" resultType="cn.iocoder.mall.order.biz.dataobject.OrderDO">
|
||||
SELECT
|
||||
<include refid="FIELDS" />
|
||||
@@ -122,9 +96,6 @@
|
||||
WHERE id = #{id}
|
||||
</select>
|
||||
|
||||
<!--
|
||||
查询条件 注意:条件顺序,避免不能使用索引
|
||||
-->
|
||||
<sql id="selectWhere">
|
||||
<if test="status != null">
|
||||
AND `status` = #{status}
|
||||
@@ -147,26 +118,22 @@
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<!--
|
||||
查询 - 后台分页page Count
|
||||
-->
|
||||
<select id="selectPageCount" resultType="java.lang.Integer">
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM `order`
|
||||
WHERE 1 = 1 <!-- TODO 芋艿 不要 1=1 ,会有问题,使用 where 标签 -->
|
||||
<include refid="selectWhere" />
|
||||
<where>
|
||||
<include refid="selectWhere" />
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<!--
|
||||
查询 - 后台分页page
|
||||
-->
|
||||
<select id="selectPage" resultType="cn.iocoder.mall.order.biz.dataobject.OrderDO">
|
||||
SELECT
|
||||
<include refid="FIELDS" />
|
||||
FROM `order`
|
||||
WHERE 1 = 1 <!-- TODO 芋艿 不要 1=1 ,会有问题,使用 where 标签 -->
|
||||
<include refid="selectWhere" />
|
||||
<where>
|
||||
<include refid="selectWhere" />
|
||||
</where>
|
||||
LIMIT ${pageNo * pageSize}, ${pageSize}
|
||||
</select>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
`type`, create_time, update_time
|
||||
) VALUES (
|
||||
#{orderId}, #{areaNo}, #{name}, #{mobile}, #{address},
|
||||
#{type}, #{createTime}, #{updateTime}
|
||||
#{type}, #{createTime,jdbcType=TIMESTAMP} , #{updateTime}
|
||||
)
|
||||
</insert>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user