开源 https://github.com/letian-tang/mybatis-sharding.git
史上最简洁的分库分表中间件
基于SpringBoot+Mybatis的分库分表
基于Mapper的切面
数据源默认使用HikariDataSource
@Component
public class ShardingStrategyImpl implements ShardingStrategy {
@Override
public Long getShardingKey() {
// 例子:从ThreadLocal中获取当前卖家id,通过卖家id sharding
return SellerIdHolder.getSellerId();
}
}
mybatis-db-sharding 分库分表
mybatis-db-example OrderServiceTest 单元测试
如果有事务,需要在开启事务之前确定数据源
那么就需要对@Transactional 和 TransactionTemplate.execute做拦截
private static final String EXPRESSION_TRANSACTIONAL =
"@annotation(org.springframework.transaction.annotation.Transactional)";
private static final String EXPRESSION_TRANSACTIONAL_TEMPLATE =
"execution(* org.springframework.transaction.support.TransactionTemplate.execute(..))";
private final String[] expressions =
new String[] {EXPRESSION_TRANSACTIONAL, EXPRESSION_TRANSACTIONAL_TEMPLATE};
/**
* 拦截器
*
* @return defaultPointcutAdvisor
*/
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor() {
List<String> expressionList = shardingProperties.getMapperPointcuts();
Assert.notEmpty(expressionList, "Mapper Pointcut is null");
DataSourceAdvice interceptor = new DataSourceAdvice(shardStrategy, shardingProperties);
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
expressionList.addAll(Arrays.asList(expressions));
String expression = String.join(" || ", expressionList);
pointcut.setExpression(expression);
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(pointcut);
advisor.setAdvice(interceptor);
return advisor;
}
#开启
mybatis.db.sharding.enabled=true
#Mapper切面,多个 逗号分隔 如 execution(* com.tdy..*Mapper.*(..)),execution(* com.tdy..*Mapper.*(..))
mybatis.db.sharding.mapper-pointcuts=execution(* com.tdy..*Mapper.*(..))
#数据库1
mybatis.db.sharding.data-sources[0].jdbc-url=jdbc:mysql://localhost:3306/sophon_0?serverTimezone=Asia/Shanghai&allowMultiQueries=true&useSSL=false&zeroDateTimeBehavior=convertToNull&useAffectedRows=true
mybatis.db.sharding.data-sources[0].username=username
mybatis.db.sharding.data-sources[0].password=password
mybatis.db.sharding.data-sources[0].maximum-pool-size=10
mybatis.db.sharding.data-sources[0].idle-timeout=10000
#数据库2
mybatis.db.sharding.data-sources[1].jdbc-url=jdbc:mysql://localhost:3306/sophon_1?serverTimezone=Asia/Shanghai&allowMultiQueries=true&useSSL=false&zeroDateTimeBehavior=convertToNull&useAffectedRows=true
mybatis.db.sharding.data-sources[1].username=username
mybatis.db.sharding.data-sources[1].password=password
mybatis.db.sharding.data-sources[1].maximum-pool-size=3
mybatis.db.sharding.data-sources[1].idle-timeout=10000
#表名t_order,nums分表数量4,不配置的表不进行分表
mybatis.db.sharding.tables.t_order.nums=4
开源 https://github.com/letian-tang/mybatis-sharding.git
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private OrderMapper orderMapper;
/**
* 单表支持
*
* @param order
*/
@Override
public void insert(Order order) {
orderMapper.insert(order);
}
/**
* @Transactional 注解事务支持
* @param orders
*/
@Override
@Transactional
public void insertBatch(List<Order> orders) {
for (Order order : orders) {
orderMapper.insert(order);
}
}
/**
* 事务模板 transactionTemplate 支持
*
* @param orders
*/
@Override
public void insertBatchTemplate(List<Order> orders) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
for (Order order : orders) {
orderMapper.insert(order);
}
}
});
}
/**
* 查询支持
*
* @return
*/
@Override
public List<Order> select() {
return orderMapper.selectList(new LambdaQueryWrapper<Order>());
}
}
单元测试
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = ShardingApplication.class)
public class OrderServiceTest {
@Autowired
private OrderService orderService;
@Before
public void init() {
SellerIdHolder.setSellerId(12L);
}
@After
public void after() {
SellerIdHolder.clear();
}
/**
* 单表
*/
@Test
public void saveOrder() {
orderService.insert(Order.builder().name("11111").build());
}
/**
* 事务方式 @Transactional
*/
@Test
public void saveOrder2() {
orderService.insertBatch(Lists.newArrayList(Order.builder().name("22222").build(),
Order.builder().name("33333").build()));
}
/**
* 事务 transactionTemplate方式
*/
@Test
public void saveOrder3() {
orderService.insertBatchTemplate(Lists.newArrayList(Order.builder().name("44444").build(),
Order.builder().name("55555").build()));
}
/**
* 查询
*/
@Test
public void selectOrder() {
orderService.select();
}
/**
* 测试 多条sql语句,分号;分隔
*/
@Test
public void saveOrder4() {
orderService.insertBatchList(Lists.newArrayList(Order.builder().name("66666").build(),
Order.builder().name("77777").build()));
}
}