springboot篇】二十一. 基於springboot電商項目 十三 分庫分表應用項目中

中國加油,武漢加油!

篇幅較長,配合目錄觀看

案例準備

  1. 本案例基於springboot篇】二十一. 基於springboot電商項目 十三 分庫分表介紹和案例

1. 分庫整合項目中

1.1 腳本環境準備

在這裏插入圖片描述

1.2 order-service-api修改Service接口

package com.wpj.service;

import com.wpj.entity.User;

public interface IOrderService {
    public int addOrder(Integer addressId, User user);
}

1.3 order-service修改ServiceImpl實現類

package com.wpj.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.wpj.common.utils.OrderUtils;
import com.wpj.entity.*;
import com.wpj.mapper.IOrderMapper;
import com.wpj.service.IAddressService;
import com.wpj.service.ICartService;
import com.wpj.service.IOrderDetailService;
import com.wpj.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class OrderServiceImpl implements IOrderService {
    @Autowired
    private IOrderMapper orderMapper;
    @Reference
    private IAddressService addressService;
    @Reference
    private ICartService cartService;
    @Reference
    private IOrderDetailService orderDetailService;
    @Autowired
    private OrderUtils orderUtils;

    @Override
    public int addOrder(Integer addressId, User user) {
        // 根據地址id查詢地址的對象
        Address address = addressService.selectById(addressId);
        List<Cart> cartList = cartService.getUserCartList(user,"");
        // 插入訂單
        Order order = new Order();
        String orderId = orderUtils.createOrderId(user.getId());
        order.setId(orderId);
        order.setUid(user.getId());
        order.setPerson(address.getPhone());
        order.setAddress(address.getAddress());
        order.setCreateTime(new Date());
        order.setOstatus(0); // 0 未支付 1 已支付 2 超時 3 取消
        order.setPerson(address.getPerson());
        order.setTotalPrice(cartService.getTotalPrice(cartList));
        // 設置數據源
        orderMapper.addOrder(order);
        // 插入訂單詳情
        List<OrderDetail> orderDetailList = new ArrayList<>();
        for (Cart cart: cartList) {
            OrderDetail orderDetail = new OrderDetail();
            Goods goods = cart.getGoods();
            orderDetail.setGprice(goods.getGprice());
            orderDetail.setGpic(goods.getGpic());
            orderDetail.setGnum(cart.getNum());
            orderDetail.setGname(goods.getGname());
            orderDetail.setGid(goods.getId());
            orderDetail.setGcount(cart.getSubTotal());
            orderDetail.setGdesc(goods.getGdesc());
            orderDetailList.add(orderDetail);

            if (orderDetailList.size() == 300) {
                orderDetailService.addBarch(orderDetailList);
                orderDetailList.clear();
            }

        }
        if (orderDetailList.isEmpty()){
            orderDetailService.addBarch(orderDetailList);
        }
        // 清空購物車
        cartService.deleteCartByUid(user.getId());
        return orderMapper.addOrder(order);
    }
}

1.4 shop-order修改Controller

@RequestMapping("/addOrder")
@IsLogin(mustUser = true)
@ResponseBody
public String addOrder(Integer addressId,User user){
    orderService.addOrder(addressId, user);
    // 跳轉到支付頁面

    return "ok";
}

1.5 修改order-service的yml

spring:
  datasource1:
    url: jdbc:mysql://localhost:3306/nz1904-springboot-shop
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
    aliases: db1
  datasource2:
    url: jdbc:mysql://localhost:3306/nz1904-springboot-shop-02
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver
    aliases: db2
  redis:
    host: 192.168.59.100
    password: admin
mybatis-plus:
  type-aliases-package: com.wpj.entity
  mapper-locations: classpath:/mapper/*.xml
dubbo:
  application:
    name: order-service
  registry:
    address: zookeeper://192.168.59.100:2181
  protocol:
    port: -1

1.6 程序入口忽略自動配置數據源

package com.wpj;

import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(scanBasePackages = "com.wpj", exclude = DataSourceAutoConfiguration.class)
@DubboComponentScan(basePackages = "com.wpj.service")
@MapperScan(basePackages = "com.wpj.mapper")
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

1.7 定義config類

1.7.1 定義BaseDataSource

package com.wpj.config;

import com.zaxxer.hikari.HikariDataSource;
import lombok.Data;

@Data
public class BaseDataSource {

    private String url;
    private String username;
    private String password;
    private String driverClassName;
    private String aliases;

    public HikariDataSource getDataSource(){
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setUsername(username);
        dataSource.setJdbcUrl(url);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClassName);
        return dataSource;
    }
}

1.7.2 定義Order1和Order2DataSource

package com.wpj.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "spring.datasource1")
public class Order1DataSource extends BaseDataSource {
}
package com.wpj.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "spring.datasource2")
public class Order2DataSource extends BaseDataSource {
}

1.7.3 定義DynamicDataSource

package com.wpj.config;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.lang.Nullable;

public class DynamicDataSource extends AbstractRoutingDataSource {

    private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    @Nullable
    @Override
    protected Object determineCurrentLookupKey() {
        return threadLocal.get();
    }

    public static void setDbName(String dbName){
        threadLocal.set(dbName);
    }
}

1.7.4 定義MyBatisConfig

package com.wpj.config;

import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class MyBatisConfig {
    @Autowired
    private Order1DataSource order1DataSource;
    @Autowired
    private Order2DataSource order2DataSource;
    @Value("${mybatis-plus.mapper-locations}")
    private String mapperLocations;
    @Bean
    public DynamicDataSource dynamicDataSource(){
        // 創建一個動態數據源
        DynamicDataSource dataSource = new DynamicDataSource();
        Map<Object,Object> map = new HashMap<>();
        map.put(order1DataSource.getAliases(),order1DataSource.getDataSource());
        map.put(order2DataSource.getAliases(),order2DataSource.getDataSource());
        // 把map放進入
        dataSource.setTargetDataSources(map);
        // 設置默認的數據源
        dataSource.setDefaultTargetDataSource(order1DataSource.getDataSource());
        return dataSource;
    }
    @Bean
    public MybatisSqlSessionFactoryBean sqlSessionFactoryBean(){
        MybatisSqlSessionFactoryBean sqlSessionFactoryBean= new MybatisSqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource());
        sqlSessionFactoryBean.setTypeAliasesPackage("com.wpj.entity");
        try {
            // 設置mapper的路徑
            sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return  sqlSessionFactoryBean;
    }
}

1.8 Test

在這裏插入圖片描述
在這裏插入圖片描述

2. 分表整合項目中

2.1 shop-mapper修改IOrderMapper接口

package com.wpj.mapper;

import com.wpj.entity.Order;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface IOrderMapper {
    public int addOrder(@Param("order") Order order, @Param("tabIndex") Integer tabIndx);
    
    void updateOrderState(@Param("map") Map<String, String> map, @Param("tabIndex") Integer tabIndex);
    
    Order selectById(@Param("oid") String oid, @Param("tabIndex") Integer tabIndex);
    
    List<Order> getOrderListByUid(@Param("uid") Integer uid, @Param("tabIndex") Integer tabIndex);
}

2.2 修改IOrderMapper.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.wpj.mapper.IOrderMapper">

    <insert id="addOrder">
		INSERT INTO t_order${tabIndex} (
			id,
			total_price,
			ocreate_time,
			ostatus,
			u_id,
			person,
			phone,
			address
		)
		VALUES
			(
			  #{order.id},
			  #{order.totalPrice},
			  #{order.createTime},
			  #{order.ostatus},
			  #{order.uid},
			  #{order.person},
			  #{order.phone},
			  #{order.address}
			)
	</insert>
</mapper>

2.3 修改IOrderDetailMapper接口

package com.wpj.mapper;

import com.wpj.entity.OrderDetail;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface IOrderDetailMapper {
    public int addBarch(@Param("list") List<OrderDetail> list, @Param("tabIndex") Integer tabIndex);
}

2.4 修改IOrderDetailMapper.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.wpj.mapper.IOrderDetailMapper">
	
	<insert id="addBarch">
		INSERT INTO t_order_detail${tabIndex} (
				id,
				oid,
				gid,
				gname,
				gprice,
				gnum,
				gcount,
				gpic,
				gdesc
			)
			VALUES
			<foreach collection="list" item="od" separator=",">
				(
					#{od.id},
					#{od.oid},
					#{od.gid},
					#{od.gname},
					#{od.gprice},
					#{od.gnum},
					#{od.gcount},
					#{od.gpic},
					#{od.gdesc}
				)
			</foreach>
	</insert>
</mapper>

2.5 order-service修改ServiceImpl實現類

@Override
public int addBarch(List<OrderDetail> list) {
    return 0;
}

2.6 order-service修改ServiceImpl實現類

package com.wpj.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.wpj.common.constant.Constants;
import com.wpj.common.utils.OrderUtils;
import com.wpj.config.DynamicDataSource;
import com.wpj.entity.*;
import com.wpj.mapper.IOrderDetailMapper;
import com.wpj.mapper.IOrderMapper;
import com.wpj.service.IAddressService;
import com.wpj.service.ICartService;
import com.wpj.service.IOrderDetailService;
import com.wpj.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class OrderServiceImpl implements IOrderService {
    @Autowired
    private IOrderMapper orderMapper;
    @Reference
    private IAddressService addressService;
    @Reference
    private ICartService cartService;
    @Autowired
    private IOrderDetailMapper orderDetailMapper;
    @Autowired
    private OrderUtils orderUtils;

    @Override
    public int addOrder(Integer addressId, User user) {
        // 根據地址id查詢地址的對象
        Address address = addressService.selectById(addressId);
        List<Cart> cartList = cartService.getUserCartList(user,"");
        // 插入訂單
        Order order = new Order();
        String orderId = orderUtils.createOrderId(user.getId());
        order.setId(orderId);
        order.setUid(user.getId());
        order.setPerson(address.getPhone());
        order.setAddress(address.getAddress());
        order.setCreateTime(new Date());
        order.setOstatus(0); // 0 未支付 1 已支付 2 超時 3 取消
        order.setPerson(address.getPerson());
        order.setTotalPrice(cartService.getTotalPrice(cartList));
        // 設置數據源
        int tabIndex = setOrderDataSource(user.getId());
        orderMapper.addOrder(order,tabIndex);
        // 插入訂單詳情
        List<OrderDetail> orderDetailList = new ArrayList<>();
        for (Cart cart: cartList) {
            OrderDetail orderDetail = new OrderDetail();
            Goods goods = cart.getGoods();
            orderDetail.setGprice(goods.getGprice());
            orderDetail.setGpic(goods.getGpic());
            orderDetail.setGnum(cart.getNum());
            orderDetail.setGname(goods.getGname());
            orderDetail.setGid(goods.getId());
            orderDetail.setGcount(cart.getSubTotal());
            orderDetail.setGdesc(goods.getGdesc());
            orderDetailList.add(orderDetail);

            if (orderDetailList.size() == 300) {
                orderDetailMapper.addBarch(orderDetailList, tabIndex);
                orderDetailList.clear();
            }

        }
        if (orderDetailList.isEmpty()){
            orderDetailMapper.addBarch(orderDetailList, tabIndex);
        }
        // 清空購物車
        cartService.deleteCartByUid(user.getId());
        return 1;
    }
    /**
     * 設置order的數據源
     * @param userId
     * @return 表的索引
     */
    public Integer setOrderDataSource(Integer userId) {
        // 獲取用戶id後四位
        Integer userIdEnd = Integer.parseInt(orderUtils.getUserIdEnd(userId));
        // 根據用戶id後四位獲取數據源編號
        Integer dbIndex = (userIdEnd % Constants.ORDER_DB_NUM)+1;
        // 設置數據源
        DynamicDataSource.setDbName("db"+dbIndex);
        // 算出表的索引
        Integer tabIndex = (userId/Constants.ORDER_TAB_NUM %Constants.ORDER_TAB_NUM )+1;
        return tabIndex;
    }
}

2.7 啓動程序入口測試

  1. 用不同id的用戶取購物,然後查看存放在那些庫中
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章