1,查看相关官方文档
https://shardingsphere.apache.org/document/legacy/3.x/document/cn/manual/sharding-jdbc/configuration/config-spring-boot/
https://baomidou.gitee.io/mybatis-plus-doc/#/tenant
https://gitee.com/baomidou/mybatisplus-spring-boot/blob/master/src/main/java/com/baomidou/springboot/config/MybatisPlusConfig.java
2,新建Maven项目,添加相关依赖
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.1.2.RELEASE
com.example
sharding-demo
0.0.1-SNAPSHOT
demo
Demo project for Spring Boot
1.8
3.1.0
1.1.12
3.1.2
1.2.58
com.baomidou
mybatis-plus-boot-starter
compile
${mybatis-plus.version}
org.springframework.boot
spring-boot-starter-web
io.shardingsphere
sharding-jdbc-spring-boot-starter
${sharding-sphere.version}
io.shardingsphere
sharding-transaction-spring-boot-starter
${sharding-sphere.version}
org.projectlombok
lombok
org.springframework.boot
spring-boot-test
test
com.alibaba
druid
${druid.version}
junit
junit
test
com.alibaba
fastjson
${fastjson.version}
mysql
mysql-connector-java
org.apache.commons
commons-lang3
org.springframework
spring-test
5.1.8.RELEASE
test
org.springframework.boot
spring-boot-maven-plugin
3,目录结构
4,application.yml
server:
port: 9999
sharding:
jdbc:
datasource:
names: ds0,ds1
ds0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/sharding_test_0?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8
username: root
password: even
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
ds1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/sharding_test_1?useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT%2B8
username: root
password: even
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
config:
sharding:
binding-tables: t_order,t_order_item
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order
t_order_item:
actual-data-nodes: ds$->{0..1}.t_order_item
default-database-strategy:
complex:
shardingColumns: user_id
algorithmClassName: com.example.demo.mybatis.sharding.WarehouseComplexShardingDB
props:
sql.show: true
# 自定义路由配置, 格式: 数据库 :分片id
db-sharding-config:
shardingColumn: user_id
shardingDbConfs:
- {"ds0": ["0","2"]}
- {"ds1": ["1","3"]}
mybatis-plus:
mapper-locations: classpath*:sqlmap/**/*.xml
type-aliases-package: com.example.demo.mybatis.entity
logging:
level:
com.baomidou.mybatisplus.samples: debug
service,mapper,entity代码用mybatis-plus自动生成
5,config
package com.example.demo.mybatis.config;
/*
* Copyright (c) 2011-2020, baomidou ([email protected]).
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
import com.baomidou.mybatisplus.autoconfigure.MybatisPlusPropertiesCustomizer;
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import io.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import io.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.mapper.ClassPathMapperScanner;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.sql.DataSource;
import java.util.List;
/**
* {@link EnableAutoConfiguration Auto-Configuration} for Mybatis. Contributes a
* {@link SqlSessionFactory} and a {@link SqlSessionTemplate}.
*
* If {@link org.mybatis.spring.annotation.MapperScan} is used, or a
* configuration file is specified as a property, those will be considered,
* otherwise this auto-configuration will attempt to register mappers based on
* the interface definitions in or under the root auto-configuration package.
*
*
* @author Eddú Meléndez
* @author Josh Long
* @author Kazuki Shimizu
* @author Eduardo Macarrón
*/
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
//@ConditionalOnSingleCandidate(ShardingDataSource.class)
@EnableConfigurationProperties(MybatisPlusProperties.class)
@AutoConfigureAfter(SpringBootConfiguration.class)
public class MybatisPlusAutoConfiguration implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration.class);
private final MybatisPlusProperties properties;
private final Interceptor[] interceptors;
private final ResourceLoader resourceLoader;
private final DatabaseIdProvider databaseIdProvider;
private final List configurationCustomizers;
private final List mybatisPlusPropertiesCustomizers;
private final ApplicationContext applicationContext;
public MybatisPlusAutoConfiguration(MybatisPlusProperties properties,
ObjectProvider interceptorsProvider,
ResourceLoader resourceLoader,
ObjectProvider databaseIdProvider,
ObjectProvider> configurationCustomizersProvider,
ObjectProvider> mybatisPlusPropertiesCustomizerProvider,
ApplicationContext applicationContext) {
this.properties = properties;
this.interceptors = interceptorsProvider.getIfAvailable();
this.resourceLoader = resourceLoader;
this.databaseIdProvider = databaseIdProvider.getIfAvailable();
this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable();
this.mybatisPlusPropertiesCustomizers = mybatisPlusPropertiesCustomizerProvider.getIfAvailable();
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() {
if (!CollectionUtils.isEmpty(mybatisPlusPropertiesCustomizers)) {
mybatisPlusPropertiesCustomizers.forEach(i -> i.customize(properties));
}
checkConfigFileExists();
}
private void checkConfigFileExists() {
if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
Assert.state(resource.exists(), "Cannot find config location: " + resource
+ " (please add config file or check your Mybatis configuration)");
}
}
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
// TODO 使用 MybatisSqlSessionFactoryBean 而不是 SqlSessionFactoryBean
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
applyConfiguration(factory);
if (this.properties.getConfigurationProperties() != null) {
factory.setConfigurationProperties(this.properties.getConfigurationProperties());
}
if (!ObjectUtils.isEmpty(this.interceptors)) {
factory.setPlugins(this.interceptors);
}
if (this.databaseIdProvider != null) {
factory.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (this.properties.getTypeAliasesSuperType() != null) {
factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
factory.setMapperLocations(this.properties.resolveMapperLocations());
}
// TODO 自定义枚举包
if (StringUtils.hasLength(this.properties.getTypeEnumsPackage())) {
factory.setTypeEnumsPackage(this.properties.getTypeEnumsPackage());
}
// TODO 此处必为非 NULL
GlobalConfig globalConfig = this.properties.getGlobalConfig();
// TODO 注入填充器
if (this.applicationContext.getBeanNamesForType(MetaObjectHandler.class,
false, false).length > 0) {
MetaObjectHandler metaObjectHandler = this.applicationContext.getBean(MetaObjectHandler.class);
globalConfig.setMetaObjectHandler(metaObjectHandler);
}
// TODO 注入主键生成器
if (this.applicationContext.getBeanNamesForType(IKeyGenerator.class, false,
false).length > 0) {
IKeyGenerator keyGenerator = this.applicationContext.getBean(IKeyGenerator.class);
globalConfig.getDbConfig().setKeyGenerator(keyGenerator);
}
// TODO 注入sql注入器
if (this.applicationContext.getBeanNamesForType(ISqlInjector.class, false,
false).length > 0) {
ISqlInjector iSqlInjector = this.applicationContext.getBean(ISqlInjector.class);
globalConfig.setSqlInjector(iSqlInjector);
}
// TODO 设置 GlobalConfig 到 MybatisSqlSessionFactoryBean
factory.setGlobalConfig(globalConfig);
return factory.getObject();
}
// TODO 入参使用 MybatisSqlSessionFactoryBean
private void applyConfiguration(MybatisSqlSessionFactoryBean factory) {
// TODO 使用 MybatisConfiguration
MybatisConfiguration configuration = this.properties.getConfiguration();
if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) {
configuration = new MybatisConfiguration();
}
if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) {
for (ConfigurationCustomizer customizer : this.configurationCustomizers) {
customizer.customize(configuration);
}
}
factory.setConfiguration(configuration);
}
@Bean
@ConditionalOnMissingBean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
ExecutorType executorType = this.properties.getExecutorType();
if (executorType != null) {
return new SqlSessionTemplate(sqlSessionFactory, executorType);
} else {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
/**
* This will just scan the same base package as Spring Boot does. If you want
* more power, you can explicitly use
* {@link org.mybatis.spring.annotation.MapperScan} but this will get typed
* mappers working correctly, out-of-the-box, similar to using Spring Data JPA
* repositories.
*/
public static class AutoConfiguredMapperScannerRegistrar
implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (!AutoConfigurationPackages.has(this.beanFactory)) {
logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
return;
}
logger.debug("Searching for mappers annotated with @Mapper");
List packages = AutoConfigurationPackages.get(this.beanFactory);
if (logger.isDebugEnabled()) {
packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg));
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
if (this.resourceLoader != null) {
scanner.setResourceLoader(this.resourceLoader);
}
scanner.setAnnotationClass(Mapper.class);
scanner.registerFilters();
scanner.doScan(StringUtils.toStringArray(packages));
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
/**
* {@link org.mybatis.spring.annotation.MapperScan} ultimately ends up
* creating instances of {@link MapperFactoryBean}. If
* {@link org.mybatis.spring.annotation.MapperScan} is used then this
* auto-configuration is not needed. If it is _not_ used, however, then this
* will bring in a bean registrar and automatically register components based
* on the same component-scanning path as Spring Boot itself.
*/
@Configuration
@Import({com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
@ConditionalOnMissingBean(MapperFactoryBean.class)
public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
@Override
public void afterPropertiesSet() {
logger.debug("No {} found.", MapperFactoryBean.class.getName());
}
}
}
package com.example.demo.mybatis.config;
import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author jiangxinjun
* @date 2019/06/12
*/
@Configuration
@MapperScan({"com.example.demo.mybatis.mapper"})
public class MybatisPlusConfig {
private static Map map = new HashMap<>();
/**
* 分页插件+多租户(自动注入user_id)
*
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
/*
* 【测试多租户】 SQL 解析处理拦截器
* 这里固定写成租户 1
*/
List sqlParserList = new ArrayList<>();
TenantSqlParser tenantSqlParser = new TenantSqlParser();
tenantSqlParser.setTenantHandler(new TenantHandler() {
@Override
public Expression getTenantId() {
return new LongValue(1L);
}
@Override
public String getTenantIdColumn() {
return "user_id";
}
@Override
public boolean doTableFilter(String tableName) {
// 这里可以判断是否过滤表
/*if ("user".equals(tableName)) {
return true;
}*/
return false;
}
});
sqlParserList.add(tenantSqlParser);
paginationInterceptor.setSqlParserList(sqlParserList);
return paginationInterceptor;
}
}
package com.example.demo.mybatis.sharding;
import com.google.common.collect.Sets;
import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author : yuqin
* @version : 1.0
* @date : 2019/6/28 10:35
*/
@Component
@Data
@ConfigurationProperties(prefix = "sharding.db-sharding-config")
@ToString
public class ShardingConf {
private static String SHARDING_COLUMN = "user_id";
private static Map> SHARDING_DB_CONF = new HashMap<>();
public void setShardingColumn(String shardingColumn){
ShardingConf.SHARDING_COLUMN = shardingColumn;
}
public void setShardingDbConfs(List
package com.example.demo.mybatis.sharding;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Sets;
import io.shardingsphere.api.algorithm.sharding.ListShardingValue;
import io.shardingsphere.api.algorithm.sharding.ShardingValue;
import io.shardingsphere.api.algorithm.sharding.complex.ComplexKeysShardingAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author snowalker
* @version 1.0
* @date 2019/3/23 10:55
* @className WarehouseComplexShardingDB
* @desc 自定义复合分片规则--数据源分片规则
*/
public class WarehouseComplexShardingDB implements ComplexKeysShardingAlgorithm {
private static final Logger log = LoggerFactory.getLogger(WarehouseComplexShardingDB.class);
/**
* @param availableDatabasesNames 可用数据源集合
* @param shardingValuesInfo 分片键
* @return sharding results for data sources or tables's names
*/
@Override
public Collection doSharding(Collection availableDatabasesNames, Collection shardingValuesInfo) {
log.info("availableDatabasesNames:" + JSON.toJSONString(availableDatabasesNames) + ",shardingValuesInfo:" + JSON.toJSONString(shardingValuesInfo));
//进入通用复杂分片算法-抽象类-数据库路由:availableDatabasesNames=["ds0","ds1","ds2","ds3"],
//shardingValuesInfo=[{"columnName":"user_id","logicTableName":"t_order","values":["1","2"]}]
if (shardingValuesInfo == null || shardingValuesInfo.isEmpty()) {
return availableDatabasesNames;
}
HashSet availableDatabasesNameSet = Sets.newHashSet(availableDatabasesNames);
Set shardingResults = new HashSet<>();
for (ShardingValue shardingValueInfo : shardingValuesInfo) {
//匹配分库列
if (!ShardingConf.getShardingColumn().equalsIgnoreCase(shardingValueInfo.getColumnName())) {
break;
}
ListShardingValue listShardingValue = (ListShardingValue) shardingValueInfo;
Collection shardingValues = listShardingValue.getValues();
log.info("shardingValue:" + JSON.toJSONString(shardingValues));
if (CollectionUtils.isEmpty(shardingValues)) {
return shardingResults;
}
//noinspection unchecked
shardingValues.forEach(shardingValue ->{
String dbName = ShardingConf.getShardingDbConf().entrySet().stream()
.filter(en-> en.getValue().contains("" + shardingValue) && availableDatabasesNameSet.contains(en.getKey()))
.findFirst()
.map(Map.Entry::getKey)
.orElseThrow(() -> new RuntimeException("sharding not find error! table : " + shardingValueInfo.getLogicTableName() + " , shardingColumn:" +shardingValueInfo.getColumnName()+" , value: " + shardingValue.toString()));
shardingResults.add(dbName);
});
}
return shardingResults;
}
}
/*
* Copyright 2016-2018 shardingsphere.io.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
/**
* @author admin
*/
@SpringBootApplication(scanBasePackages = {"com.example.demo"},exclude = DataSourceAutoConfiguration.class)
public class SpringBootStarterExample {
public static void main(String[] args) {
SpringApplication.run(SpringBootStarterExample.class, args);
}
}
注意:1,数据源有冲突,启动类排除掉DataSourceAutoConfiguration
2,MybatisPlusConfig 中的getTenantId自己实现(可从cookie或者ThreadLocal获取)
3,MybatisPlusAutoConfiguration 来自mybatis-plus-boot-start-3.1.2jar
注释掉@ConditionalOnSingleCandidate(DataSource.class)
表
0库
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`des` varchar(100) NOT NULL,
`total_price` decimal(10,3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_order
-- ----------------------------
INSERT INTO `t_order` VALUES ('2', '2', '白菜、可乐、香蕉', '6.000');
-- ----------------------------
-- Table structure for t_order_item
-- ----------------------------
DROP TABLE IF EXISTS `t_order_item`;
CREATE TABLE `t_order_item` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`goods_name` varchar(100) NOT NULL,
`price` decimal(10,3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_order_item
-- ----------------------------
INSERT INTO `t_order_item` VALUES ('4', '2', '2', '白菜', '1.000');
INSERT INTO `t_order_item` VALUES ('5', '2', '2', '可乐', '2.000');
INSERT INTO `t_order_item` VALUES ('6', '2', '2', '香蕉', '3.000');
1库
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for t_order
-- ----------------------------
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`des` varchar(100) NOT NULL,
`total_price` decimal(10,3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_order
-- ----------------------------
INSERT INTO `t_order` VALUES ('1', '1', '白菜、可乐、香蕉', '6.000');
-- ----------------------------
-- Table structure for t_order_item
-- ----------------------------
DROP TABLE IF EXISTS `t_order_item`;
CREATE TABLE `t_order_item` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`goods_name` varchar(100) NOT NULL,
`price` decimal(10,3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_order_item
-- ----------------------------
INSERT INTO `t_order_item` VALUES ('1', '1', '1', '白菜', '1.000');
INSERT INTO `t_order_item` VALUES ('2', '1', '1', '可乐', '2.000');
INSERT INTO `t_order_item` VALUES ('3', '1', '1', '香蕉', '3.000');