SpringBoot整合sharding-jdbc實現(xiàn)自定義分庫分表的實踐
一、前言
SpringBoot整合sharding-jdbc實現(xiàn)分庫分表與讀寫分離
本文將通過自定義算法來實現(xiàn)定制化的分庫分表來擴展相應業(yè)務
二、簡介
1、分片鍵
用于數(shù)據(jù)庫/表拆分的關鍵字段
ex: 用戶表根據(jù)user_id取模拆分到不同的數(shù)據(jù)庫中
2、分片算法
- 精確分片算法
- 范圍分片算法
- 復合分片算法
- Hint分片算法
3、分片策略(分片鍵+分片算法)
- 行表達式分片策略
- 標準分片策略
- 復合分片策略
- Hint分片策略
- 不分片策略
可查看源碼 org.apache.shardingsphere.core.yaml.config.sharding.YamlShardingStrategyConfiguration

三、程序實現(xiàn)
溫馨小提示:詳情可查看案例demo源碼

這里先貼出完整的application.yml配置,后面實現(xiàn)每一種分片策略時,放開其相應配置即可~
# sharding-jdbc配置
spring:
shardingsphere:
# 是否開啟SQL顯示
props:
sql:
show: true
# ====================== ↓↓↓↓↓↓ 數(shù)據(jù)源配置 ↓↓↓↓↓↓ ======================
datasource:
names: ds-master-0,ds-slave-0-1,ds-slave-0-2,ds-master-1,ds-slave-1-1,ds-slave-1-2
# ====================== ↓↓↓↓↓↓ 配置第1個主從庫 ↓↓↓↓↓↓ ======================
# 主庫1
ds-master-0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/ds0?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false # MySQL在高版本需要指明是否進行SSL連接 解決則加上 &useSSL=false
username: root
password: root
# 主庫1-從庫1
ds-slave-0-1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3307/ds0?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false # MySQL在高版本需要指明是否進行SSL連接 解決則加上 &useSSL=false
username: root
password: root
# 主庫1-從庫2
ds-slave-0-2:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3307/ds0?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false # MySQL在高版本需要指明是否進行SSL連接 解決則加上 &useSSL=false
username: root
password: root
# ====================== ↓↓↓↓↓↓ 配置第2個主從庫 ↓↓↓↓↓↓ ======================
# 主庫2
ds-master-1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/ds1?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false # MySQL在高版本需要指明是否進行SSL連接 解決則加上 &useSSL=false
username: root
password: root
# 主庫2-從庫1
ds-slave-1-1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3307/ds1?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false # MySQL在高版本需要指明是否進行SSL連接 解決則加上 &useSSL=false
username: root
password: root
# 主庫2-從庫2
ds-slave-1-2:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3307/ds1?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false # MySQL在高版本需要指明是否進行SSL連接 解決則加上 &useSSL=false
username: root
password: root
sharding:
# ====================== ↓↓↓↓↓↓ 讀寫分離配置 ↓↓↓↓↓↓ ======================
master-slave-rules:
ds-master-0:
# 主庫
masterDataSourceName: ds-master-0
# 從庫
slaveDataSourceNames:
- ds-slave-0-1
- ds-slave-0-2
# 從庫查詢數(shù)據(jù)的負載均衡算法 目前有2種算法 round_robin(輪詢)和 random(隨機)
# 算法接口 org.apache.shardingsphere.spi.masterslave.MasterSlaveLoadBalanceAlgorithm
# 實現(xiàn)類 RandomMasterSlaveLoadBalanceAlgorithm 和 RoundRobinMasterSlaveLoadBalanceAlgorithm
loadBalanceAlgorithmType: ROUND_ROBIN
ds-master-1:
masterDataSourceName: ds-master-1
slaveDataSourceNames:
- ds-slave-1-1
- ds-slave-1-2
loadBalanceAlgorithmType: ROUND_ROBIN
# ====================== ↓↓↓↓↓↓ 分庫分表配置 ↓↓↓↓↓↓ ======================
tables:
t_user:
actual-data-nodes: ds-master-$->{0..1}.t_user$->{0..1}
# 配置屬性可參考 org.apache.shardingsphere.core.yaml.config.sharding.YamlShardingStrategyConfiguration
# =========== ↓↓↓↓↓↓ 行表達式分片策略 ↓↓↓↓↓↓ ===========
# 在配置中使用 Groovy 表達式,提供對 SQL語句中的 = 和 IN 的分片操作支持,只支持單分片健。
# # ====== ↓↓↓↓↓↓ 分庫 ↓↓↓↓↓↓ ======
# database-strategy:
# inline:
# sharding-column: user_id # 添加數(shù)據(jù)分庫字段(根據(jù)字段插入數(shù)據(jù)到哪個庫 ex:user_id)
# algorithm-expression: ds-master-$->{user_id % 2} # 根據(jù)user_id取模拆分到不同的庫中
# # ====== ↓↓↓↓↓↓ 分表 ↓↓↓↓↓↓ ======
# table-strategy:
# inline:
# sharding-column: sex # 添加數(shù)據(jù)分表字段(根據(jù)字段插入數(shù)據(jù)到哪個表 ex:sex)
# algorithm-expression: t_user$->{sex % 2} # 分片算法表達式 => 根據(jù)用戶性別取模拆分到不同的表中
# =========== ↓↓↓↓↓↓ 標準分片策略 ↓↓↓↓↓↓ ===========
# 精確分片算法 => sql在分庫/分表鍵上執(zhí)行 = 與 IN 時觸發(fā)計算邏輯,否則不走分庫/分表,全庫/全表執(zhí)行。
# database-strategy:
# standard:
# sharding-column: user_id # 分庫用到的鍵
# precise-algorithm-class-name: com.zhengqing.demo.config.sharding.precise.MyDbPreciseShardingAlgorithm # 自定義分庫算法實現(xiàn)類
# table-strategy:
# standard:
# sharding-column: sex # 添加數(shù)據(jù)分表字段(根據(jù)字段插入數(shù)據(jù)到那個表 ex:sex)
# precise-algorithm-class-name: com.zhengqing.demo.config.sharding.precise.MyTablePreciseShardingAlgorithm # 自定義分表算法實現(xiàn)類
# 范圍分片算法 => sql在分庫/分表鍵上執(zhí)行 BETWEEN AND、>、<、>=、<= 時觸發(fā)計算邏輯,否則不走分庫/分表,全庫/全表執(zhí)行。
# database-strategy:
# standard:
# sharding-column: user_id
# precise-algorithm-class-name: com.zhengqing.demo.config.sharding.range.MyDbPreciseShardingAlgorithm
# range-algorithm-class-name: com.zhengqing.demo.config.sharding.range.MyDbRangeShardingAlgorithm
# table-strategy:
# standard:
# sharding-column: sex
# precise-algorithm-class-name: com.zhengqing.demo.config.sharding.range.MyTablePreciseShardingAlgorithm
# range-algorithm-class-name: com.zhengqing.demo.config.sharding.range.MyTableRangeShardingAlgorithm
# =========== ↓↓↓↓↓↓ 復合分片策略 ↓↓↓↓↓↓ ===========
# SQL 語句中有>,>=, <=,<,=,IN 和 BETWEEN AND 等操作符,不同的是復合分片策略支持對多個分片健操作。
# database-strategy:
# complex:
# sharding-columns: user_id,sex
# algorithm-class-name: com.zhengqing.demo.config.sharding.complex.MyDbComplexKeysShardingAlgorithm
# table-strategy:
# complex:
# sharding-columns: user_id,sex
# algorithm-class-name: com.zhengqing.demo.config.sharding.complex.MyTableComplexKeysShardingAlgorithm
# =========== ↓↓↓↓↓↓ hint分片策略 ↓↓↓↓↓↓ ===========
# 通過 Hint API實現(xiàn)個性化配置 => 可查看 com.zhengqing.demo.service.impl.UserServiceImpl.listPageForHint
database-strategy:
hint:
algorithm-class-name: com.zhengqing.demo.config.sharding.hint.MyDbHintShardingAlgorithm
table-strategy:
hint:
algorithm-class-name: com.zhengqing.demo.config.sharding.hint.MyTableHintShardingAlgorithm
1、行表達式分片策略
# =========== ↓↓↓↓↓↓ 行表達式分片策略 ↓↓↓↓↓↓ ===========
# 在配置中使用 Groovy 表達式,提供對 SQL語句中的 = 和 IN 的分片操作支持,只支持單分片健。
# ====== ↓↓↓↓↓↓ 分庫 ↓↓↓↓↓↓ ======
database-strategy:
inline:
sharding-column: user_id # 添加數(shù)據(jù)分庫字段(根據(jù)字段插入數(shù)據(jù)到哪個庫 ex:user_id)
algorithm-expression: ds-master-$->{user_id % 2} # 根據(jù)user_id取模拆分到不同的庫中
# ====== ↓↓↓↓↓↓ 分表 ↓↓↓↓↓↓ ======
table-strategy:
inline:
sharding-column: sex # 添加數(shù)據(jù)分表字段(根據(jù)字段插入數(shù)據(jù)到哪個表 ex:sex)
algorithm-expression: t_user$->{sex % 2} # 分片算法表達式 => 根據(jù)用戶性別取模拆分到不同的表中
2、標準分片策略
A: 精確分片算法
# 精確分片算法 => sql在分庫/分表鍵上執(zhí)行 = 與 IN 時觸發(fā)計算邏輯,否則不走分庫/分表,全庫/全表執(zhí)行。
database-strategy:
standard:
sharding-column: user_id # 分庫用到的鍵
precise-algorithm-class-name: com.zhengqing.demo.config.sharding.precise.MyDbPreciseShardingAlgorithm # 自定義分庫算法實現(xiàn)類
table-strategy:
standard:
sharding-column: sex # 添加數(shù)據(jù)分表字段(根據(jù)字段插入數(shù)據(jù)到那個表 ex:sex)
precise-algorithm-class-name: com.zhengqing.demo.config.sharding.precise.MyTablePreciseShardingAlgorithm # 自定義分表算法實現(xiàn)類
@Slf4j
public class MyDbPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
/**
* 分片策略
*
* @param dbNameList 所有數(shù)據(jù)源
* @param shardingValue SQL執(zhí)行時傳入的分片值
* @return 數(shù)據(jù)源名稱
*/
@Override
public String doSharding(Collection<String> dbNameList, PreciseShardingValue<Long> shardingValue) {
log.info("[MyDbPreciseShardingAlgorithm] SQL執(zhí)行時傳入的分片值: [{}]", shardingValue);
// 根據(jù)user_id取模拆分到不同的庫中
Long userId = shardingValue.getValue();
for (String dbNameItem : dbNameList) {
if (dbNameItem.endsWith(String.valueOf(userId % 2))) {
return dbNameItem;
}
}
return null;
}
}
@Slf4j
public class MyTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<Byte> {
/**
* 分片策略
*
* @param tableNameList 所有表名
* @param shardingValue SQL執(zhí)行時傳入的分片值
* @return 表名
*/
@Override
public String doSharding(Collection<String> tableNameList, PreciseShardingValue<Byte> shardingValue) {
log.info("[MyTablePreciseShardingAlgorithm] SQL執(zhí)行時傳入的分片值: [{}]", shardingValue);
// 根據(jù)用戶性別取模拆分到不同的表中
Byte sex = shardingValue.getValue();
for (String tableNameItem : tableNameList) {
if (tableNameItem.endsWith(String.valueOf(sex % 2))) {
return tableNameItem;
}
}
return null;
}
}
B: 范圍分片算法
# 范圍分片算法 => sql在分庫/分表鍵上執(zhí)行 BETWEEN AND、>、<、>=、<= 時觸發(fā)計算邏輯,否則不走分庫/分表,全庫/全表執(zhí)行。
database-strategy:
standard:
sharding-column: user_id
precise-algorithm-class-name: com.zhengqing.demo.config.sharding.range.MyDbPreciseShardingAlgorithm
range-algorithm-class-name: com.zhengqing.demo.config.sharding.range.MyDbRangeShardingAlgorithm
table-strategy:
standard:
sharding-column: sex
precise-algorithm-class-name: com.zhengqing.demo.config.sharding.range.MyTablePreciseShardingAlgorithm
range-algorithm-class-name: com.zhengqing.demo.config.sharding.range.MyTableRangeShardingAlgorithm
@Slf4j
public class MyDbPreciseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
/**
* 分片策略
*
* @param dbNameList 所有數(shù)據(jù)源
* @param shardingValue SQL執(zhí)行時傳入的分片值
* @return 數(shù)據(jù)源名稱
*/
@Override
public String doSharding(Collection<String> dbNameList, PreciseShardingValue<Long> shardingValue) {
log.info("[MyDbPreciseShardingAlgorithm] SQL執(zhí)行時傳入的分片值: [{}]", shardingValue);
// 根據(jù)user_id取模拆分到不同的庫中
Long userId = shardingValue.getValue();
for (String dbNameItem : dbNameList) {
if (dbNameItem.endsWith(String.valueOf(userId % 2))) {
return dbNameItem;
}
}
return null;
}
}
@Slf4j
public class MyDbRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> dbNameList, RangeShardingValue<Long> shardingValue) {
log.info("[MyDbRangeShardingAlgorithm] shardingValue: [{}]", shardingValue);
List<String> result = Lists.newLinkedList();
int dbSize = dbNameList.size();
// 從sql 中獲取 Between 1 and 1000 的值
// lower:1
// upper:1000
Range<Long> rangeValue = shardingValue.getValueRange();
Long lower = rangeValue.lowerEndpoint();
Long upper = rangeValue.upperEndpoint();
// 根據(jù)范圍值取偶選擇庫
for (Long i = lower; i <= upper; i++) {
for (String dbNameItem : dbNameList) {
if (dbNameItem.endsWith(String.valueOf(i % 2))) {
result.add(dbNameItem);
}
if (result.size() >= dbSize) {
return result;
}
}
}
return result;
}
}
@Slf4j
public class MyTablePreciseShardingAlgorithm implements PreciseShardingAlgorithm<Byte> {
/**
* 分片策略
*
* @param tableNameList 所有表名
* @param shardingValue SQL執(zhí)行時傳入的分片值
* @return 表名
*/
@Override
public String doSharding(Collection<String> tableNameList, PreciseShardingValue<Byte> shardingValue) {
log.info("[MyTablePreciseShardingAlgorithm] SQL執(zhí)行時傳入的分片值: [{}]", shardingValue);
// 根據(jù)用戶性別取模拆分到不同的表中
Byte sex = shardingValue.getValue();
for (String tableNameItem : tableNameList) {
if (tableNameItem.endsWith(String.valueOf(sex % 2))) {
return tableNameItem;
}
}
return null;
}
}
@Slf4j
public class MyTableRangeShardingAlgorithm implements RangeShardingAlgorithm<Byte> {
@Override
public Collection<String> doSharding(Collection<String> tableNameList, RangeShardingValue<Byte> shardingValue) {
log.info("[MyTableRangeShardingAlgorithm] shardingValue: [{}]", shardingValue);
Set<String> tableNameResultList = new LinkedHashSet<>();
Range<Byte> rangeValue = shardingValue.getValueRange();
Byte lower = rangeValue.lowerEndpoint();
Byte upper = rangeValue.upperEndpoint();
// between 0 and 1
// 根據(jù)性別值選擇表
for (String tableNameItem : tableNameList) {
if (tableNameItem.endsWith(String.valueOf(lower))
|| tableNameItem.endsWith(String.valueOf(upper))) {
tableNameResultList.add(tableNameItem);
}
}
return tableNameResultList;
}
}
3、復合分片策略
# =========== ↓↓↓↓↓↓ 復合分片策略 ↓↓↓↓↓↓ ===========
# SQL 語句中有>,>=, <=,<,=,IN 和 BETWEEN AND 等操作符,不同的是復合分片策略支持對多個分片健操作。
database-strategy:
complex:
sharding-columns: user_id,sex
algorithm-class-name: com.zhengqing.demo.config.sharding.complex.MyDbComplexKeysShardingAlgorithm
table-strategy:
complex:
sharding-columns: user_id,sex
algorithm-class-name: com.zhengqing.demo.config.sharding.complex.MyTableComplexKeysShardingAlgorithm
@Slf4j
public class MyDbComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<String> {
@Override
public Collection<String> doSharding(Collection<String> dbNameList, ComplexKeysShardingValue<String> complexKeysShardingValue) {
log.info("[MyDbComplexKeysShardingAlgorithm] complexKeysShardingValue: [{}]", complexKeysShardingValue);
List<String> dbResultList = new ArrayList<>();
int dbSize = dbNameList.size();
// 得到每個分片健對應的值
// 用戶id 范圍查詢
Range<String> rangeUserId = complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("user_id");
// 性別
List<String> sexValueList = this.getShardingValue(complexKeysShardingValue, "sex");
// 對兩個分片健進行邏輯操作,選擇最終數(shù)據(jù)進哪一庫? TODO
for (String sex : sexValueList) {
String suffix = String.valueOf(Long.parseLong(sex) % 2);
for (String dbNameItem : dbNameList) {
if (dbNameItem.endsWith(suffix)) {
dbResultList.add(dbNameItem);
}
if (dbResultList.size() >= dbSize) {
return dbResultList;
}
}
}
return dbResultList;
}
private List<String> getShardingValue(ComplexKeysShardingValue<String> shardingValues, final String key) {
List<String> valueList = new ArrayList<>();
Map<String, Collection<String>> columnNameAndShardingValuesMap = shardingValues.getColumnNameAndShardingValuesMap();
if (columnNameAndShardingValuesMap.containsKey(key)) {
valueList.addAll(columnNameAndShardingValuesMap.get(key));
}
return valueList;
}
}
@Slf4j
public class MyTableComplexKeysShardingAlgorithm implements ComplexKeysShardingAlgorithm<Long> {
@Override
public Collection<String> doSharding(Collection<String> tableNameList, ComplexKeysShardingValue<Long> complexKeysShardingValue) {
log.info("[MyTableComplexKeysShardingAlgorithm] complexKeysShardingValue: [{}]", complexKeysShardingValue);
Set<String> tableNameResultList = new LinkedHashSet<>();
int tableSize = tableNameList.size();
// 用戶id 范圍查詢
Range<Long> rangeUserId = complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("user_id");
Long lower = rangeUserId.lowerEndpoint();
Long upper = rangeUserId.upperEndpoint();
// 根據(jù)user_id選擇表 TODO ...
for (String tableNameItem : tableNameList) {
if (tableNameItem.endsWith(String.valueOf(lower % 2))
|| tableNameItem.endsWith(String.valueOf(upper % 2))) {
tableNameResultList.add(tableNameItem);
}
if (tableNameResultList.size() >= tableSize) {
return tableNameResultList;
}
}
return tableNameResultList;
}
}
4、Hint分片策略
#=========== ↓↓↓↓↓↓ hint分片策略 ↓↓↓↓↓↓ ===========
# 通過 Hint API實現(xiàn)個性化配置 => 可查看 com.zhengqing.demo.service.impl.UserServiceImpl.listPageForHint
database-strategy:
hint:
algorithm-class-name: com.zhengqing.demo.config.sharding.hint.MyDbHintShardingAlgorithm
table-strategy:
hint:
algorithm-class-name: com.zhengqing.demo.config.sharding.hint.MyTableHintShardingAlgorithm
@Slf4j
public class MyDbHintShardingAlgorithm implements HintShardingAlgorithm<Integer> {
@Override
public Collection<String> doSharding(Collection<String> dbNameList, HintShardingValue<Integer> hintShardingValue) {
log.info("[MyDbHintShardingAlgorithm] hintShardingValue: [{}]", hintShardingValue);
Collection<String> dbResultList = new ArrayList<>();
int dbSize = dbNameList.size();
for (String dbNameItem : dbNameList) {
for (Integer shardingValue : hintShardingValue.getValues()) {
if (dbNameItem.endsWith(String.valueOf(shardingValue % 2))) {
dbResultList.add(dbNameItem);
}
if (dbResultList.size() >= dbSize) {
return dbResultList;
}
}
}
return dbResultList;
}
}
@Slf4j
public class MyTableHintShardingAlgorithm implements HintShardingAlgorithm<Integer> {
@Override
public Collection<String> doSharding(Collection<String> tableNameList, HintShardingValue<Integer> hintShardingValue) {
log.info("[MyTableHintShardingAlgorithm] hintShardingValue: [{}]", hintShardingValue);
Collection<String> tableResultList = new ArrayList<>();
int tableSize = tableNameList.size();
Collection<Integer> hintShardingValueValueList = hintShardingValue.getValues();
for (String tableName : tableNameList) {
for (Integer shardingValue : hintShardingValueValueList) {
if (tableName.endsWith(String.valueOf(shardingValue % 2))) {
tableResultList.add(tableName);
}
if (tableResultList.size() >= tableSize) {
return tableResultList;
}
}
}
return tableResultList;
}
}
使用時動態(tài)觸發(fā)如下:
public IPage<User> listPageForHint() {
// 清除掉上一次的規(guī)則,否則會報錯
HintManager.clear();
// HintManager API 工具類實例
HintManager hintManager = HintManager.getInstance();
// 庫 => 主要是將value值傳送到 MyDbHintShardingAlgorithm 中做邏輯分庫處理
hintManager.addDatabaseShardingValue("t_user", 100);
hintManager.addDatabaseShardingValue("t_user", 1000);
// 指定表的分片健 => 指定查t_user0
hintManager.addTableShardingValue("t_user", 0);
// hintManager.addTableShardingValue("t_user", 1);
// 讀寫分離強制讀主庫,避免造成主從復制導致的延遲
hintManager.setMasterRouteOnly();
// 查詢數(shù)據(jù)
Page<User> result = this.userMapper.selectPage(new Page<>(1, 10),
new LambdaQueryWrapper<User>()
.eq(User::getSex, "0")
.between(User::getUserId, 1L, 1000L)
);
// 清除規(guī)則
hintManager.close();
return result;
}
運行項目,接口文檔:http://127.0.0.1/doc.html 提供了幾個測試api如下

本文案例demo源碼
https://gitee.com/zhengqingya/java-workspace
到此這篇關于SpringBoot整合sharding-jdbc實現(xiàn)自定義分庫分表的實踐的文章就介紹到這了,更多相關SpringBoot sharding-jdbc自定義分庫分表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
利用Java如何獲取Mybatis動態(tài)生成的sql接口實現(xiàn)
MyBatis 的強大特性之一便是它的動態(tài)SQL,下面這篇文章主要給大家介紹了關于利用Java如何獲取Mybatis動態(tài)生成的sql接口實現(xiàn)的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-01-01
Java的Spring框架中bean的繼承與內(nèi)部bean的注入
這篇文章主要介紹了Java的Spring框架中bean的繼承與內(nèi)部bean的注入,Spring框架是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12
JAVA參數(shù)傳遞方式實例淺析【按值傳遞與引用傳遞區(qū)別】
這篇文章主要介紹了JAVA參數(shù)傳遞方式,結合實例形式分析了java按值傳遞與引用傳遞區(qū)別及相關操作注意事項,需要的朋友可以參考下2020-05-05
JavaSwing坦克大戰(zhàn)游戲的設計和實現(xiàn)
JavaSwing坦克大戰(zhàn)游戲的設計要有圖形用戶界面,界面能夠反映游戲所有的細節(jié),在最終呈現(xiàn)的游戲中也要滿足所有需求,感興趣的小伙伴一起來看看吧2021-08-08

