アリー分散型データベースシステム中間部品-cobarculientライブラリ(基本原理)
cobarcelient分庫の基本原理(分庫はどうやって実現しますか?)
一:hashFunctionを構成することによって、どのように該当するアクセス先のデータベースセグメントを見つけることができますか?
1.筆者の最初の文章(cobarcrentライブラリの基本的な構成)を通して、その文章を読んだら、次のような構成によって該当するデータベースセグメントにルーティングされるかもしれないことが分かります。
二:cobarcelientのMysdalSql MapClint Templateはどうやってルータの対象SimpleRouterを使って分庫を実現しますか?
1.プロファイルの構成はどうなりますか?
ソースは以下の通りです。
一:hashFunctionを構成することによって、どのように該当するアクセス先のデータベースセグメントを見つけることができますか?
1.筆者の最初の文章(cobarcrentライブラリの基本的な構成)を通して、その文章を読んだら、次のような構成によって該当するデータベースセグメントにルーティングされるかもしれないことが分かります。
classpath:spring/namespace-rules.xml
classpath:spring/no-namespace-rules.xml
このSimpleRouter FactoryBenは主に何をしていますか?先にここで皆さんに教えておきますが、実例化と初期化のための一つのタイプはSimpleRouterオブジェクトですが、それはどのように初期化されましたか?名の通りSimpleRouterの対象はルートの過程でまたどんな役を演じていますか?ソースコードを見てください。2.SimpleRouter FactoryBern Factory Bernを実現しました。InitializingBenインターフェースは、次のafterPropertiessetメソッドのソースです。public class SimpleRouterFactoryBean implements FactoryBean, InitializingBean {
// Resource
private Resource configLocation;
// Resource
private Resource[] configLocations;
// ( id="router" bean )
private SimpleRouter router = null;
// name="functions"
private Map functions;
// name="shards"
private Set shards;
public SimpleRouterFactoryBean() {
}
/**
* 1. ====》allRules,2. allRules ===》 router
*/
public void afterPropertiesSet() throws Exception {
//1.1
List allRules = new ArrayList();
//1.2
if (this.getConfigLocation() != null) {
List rules = this.loadRules(this.configLocation);
if (!CollectionUtils.isEmpty(rules)) {
allRules.addAll(rules);
}
}
//1.3
if (!ObjectUtils.isEmpty(this.getConfigLocations())) {
Resource[] arr$ = this.getConfigLocations();
int len$ = arr$.length;
for(int i$ = 0; i$ < len$; ++i$) {
Resource res = arr$[i$];
List rules = this.loadRules(res);
if (!CollectionUtils.isEmpty(rules)) {
allRules.addAll(rules);
}
}
}
if (!CollectionUtils.isEmpty(allRules)) {
//2.1 set shards Map ,key=Shard id,value=Shard
Map shardMap = this.convertShardMap(this.shards);
//2.2
Set routes = new LinkedHashSet();
Route route;
//2.3 allRules routes
for(Iterator i$ = allRules.iterator(); i$.hasNext(); routes.add(route)) {
InternalRule rule = (InternalRule)i$.next();
String sqlmap = rule.getSqlmap();
if (sqlmap == null || sqlmap.equals("")) {
//2.4 sqlmap , sqlmap , namespace
// sqlmap
sqlmap = rule.getNamespace();
}
//2.5 shards ,( id )
String[] shardArr = rule.getShards().split(",");
//2.6 route “shards” ( )
Set subShard = new LinkedHashSet();
String[] arr$ = shardArr;
int len$ = shardArr.length;
for(int i$ = 0; i$ < len$; ++i$) {
String shardId = arr$[i$];
//2.7 shardId Shard
Shard tempShard = (Shard)shardMap.get(shardId);
if (tempShard == null) {
throw new NullPointerException("shard:" + shardId + " is not exists");
}
//2.8 Shard
subShard.add(tempShard);
}
//2.9 shardingExpression, route “expression”
if (null != rule.getShardingExpression()) {
if (null == this.functions) {
// , functions , this.functions = new HashMap(),
// :
// , appType%2==0
//
this.functions = new HashMap();
}
//2.10 sqlmap,rule.getShardingExpression,this.functions,subShard route
route = new Route(sqlmap, new MVELExpression(rule.getShardingExpression(), this.functions), subShard);
} else {
route = new Route(sqlmap, (Expression)null, subShard);
}
}
//2.11 router,, ?
this.router = new SimpleRouter(routes);
} else {
//2.13
this.router = new SimpleRouter((Set)null);
}
}
private Map convertShardMap(Set shards) {
Map shardMap = new HashMap();
Iterator i$ = shards.iterator();
while(i$.hasNext()) {
Shard shard = (Shard)i$.next();
shardMap.put(shard.getId(), shard);
}
return shardMap;
}
// XStream ====》List
private List loadRules(Resource configLocation) throws Exception {
XStream xstream = new XStream();
xstream.alias("rules", InternalRules.class);
xstream.alias("rule", InternalRule.class);
xstream.addImplicitCollection(InternalRules.class, "rules");
xstream.useAttributeFor(InternalRule.class, "merger");
InternalRules internalRules = (InternalRules)xstream.fromXML(configLocation.getInputStream());
return internalRules.getRules();
}
public Router getObject() throws Exception {
return this.router;
}
public Class getObjectType() {
return Router.class;
}
public boolean isSingleton() {
return true;
}
public Resource getConfigLocation() {
return this.configLocation;
}
public void setConfigLocation(Resource configLocation) {
this.configLocation = configLocation;
}
public Resource[] getConfigLocations() {
return this.configLocations;
}
public void setConfigLocations(Resource[] configLocations) {
this.configLocations = configLocations;
}
public Map getFunctions() {
return this.functions;
}
public void setFunctions(Map functions) {
this.functions = functions;
}
public Set getShards() {
return this.shards;
}
public void setShards(Set shards) {
this.shards = shards;
}
}
3.ルートルールの対象public class InternalRule {
private String namespace;
private String sqlmap;
private String shardingExpression;
// Shard id( , )
private String shards;
private String merger;
.........
}
4.データベースセグメントオブジェクトpublic class Shard {
// id
private String id;
//
private DataSource dataSource;
// ( )
private String description;
......
}
5.簡単なルータの対象public class SimpleRouter implements Router {
protected Logger logger = Logger.getLogger("SimpleRouter");
private Map routes = new HashMap();
private Set EMPTY_SHARD_SET = new HashSet();
public SimpleRouter(Set routeSet) {
if (routeSet != null && !routeSet.isEmpty()) {
//1. routeSet===》 routes
Iterator i$ = routeSet.iterator();
while(i$.hasNext()) {
Route route = (Route)i$.next();
if (!this.routes.containsKey(route.getSqlmap())) {
//2.key=route sqlmap ,value=RouteGroup , sqlmap , ,
this.routes.put(route.getSqlmap(), new RouteGroup());
}
if (route.getExpression() == null) {
//3. expression Route , sqlmap
((RouteGroup)this.routes.get(route.getSqlmap())).setFallbackRoute(route);
} else {
//4. expression Route , sqlmap expression
((RouteGroup)this.routes.get(route.getSqlmap())).getSpecificRoutes().add(route);
}
}
}
}
** 3 4
GeneralMallUser
hash.generalApply(appType) == 1
master12
GeneralMallUser
hash.generalApply(appType) == 2
master13
GeneralMallUser
hash.generalApply(appType) == 3
master15
**
/**
*
* action:=AllPlatformUser.insertAllPlatformUser
**/
public Set route(String action, Object argument) {
Route resultRoute = this.findRoute(action, argument);
if (resultRoute == null && action != null) {
String namespace = action.substring(0, action.lastIndexOf("."));
resultRoute = this.findRoute(namespace, argument);
}
return resultRoute == null ? this.EMPTY_SHARD_SET : resultRoute.getShards();
}
/**
* action(sqlmap id) argument Route
**/
protected Route findRoute(String action, Object argument) {
if (this.routes.containsKey(action)) {
RouteGroup routeGroup = (RouteGroup)this.routes.get(action);
//1. routeGroup specificRoutes (expression null )
Iterator i$ = routeGroup.getSpecificRoutes().iterator();
while(i$.hasNext()) {
Route route = (Route)i$.next();
if (route.apply(action, argument)) {
return route;
}
}
//2. routeGroup fallbackRoute
if (routeGroup.getFallbackRoute() != null && routeGroup.getFallbackRoute().apply(action, argument)) {
return routeGroup.getFallbackRoute();
}
}
return null;
}
}
public interface Router {
Set route(String action, Object argument);
}
6.ルートの対象(とりあえずこう呼びましょう)public class Route {
private String sqlmap;
private Expression expression;
private Set shards;
public Route(String sqlmap, Expression expression, Set shards) {
this.sqlmap = sqlmap;
this.expression = expression;
this.shards = shards;
}
/**
* action(sqlmap) sql Route( )
*/
public boolean apply(String action, Object argument) {
if (this.sqlmap == null) {
return false;
} else if (!this.sqlmap.equals(action)) {
return false;
} else if (this.expression == null) {
return true;
} else {
return this.expression != null && argument != null && this.expression.apply(argument);
}
}
}
7.ルートグループのオブジェクトpublic class RouteGroup {
//expression null
private Route fallbackRoute = null;
//expression null
private Set specificRoutes = new HashSet();
public RouteGroup() {
}
public RouteGroup(Route fallbackRoute, Set specificRoutes) {
this.fallbackRoute = fallbackRoute;
if (specificRoutes != null && !specificRoutes.isEmpty()) {
this.specificRoutes.addAll(specificRoutes);
}
}
public Route getFallbackRoute() {
return this.fallbackRoute;
}
public void setFallbackRoute(Route fallbackRoute) {
this.fallbackRoute = fallbackRoute;
}
public Set getSpecificRoutes() {
return this.specificRoutes;
}
public void setSpecificRoutes(Set specificRoutes) {
this.specificRoutes = specificRoutes;
}
}
8.上記のソースコードの分析を通して、SimpleRouter FactoryBeanの役割をよく知ることができます。1.ルート規則の配置ファイル==>allRulesを解析し、2.allRulesの集合==簡単なルータオブジェクトrouterを解析します。ルータオブジェクトSimpleRouterのroute方法では、route方法は、2つの重要なパラメータactionとargmentを通じて適切なデータベースセグメントを正確に見つけることができます。この方法は、データアクセスにおいて、それぞれのデータベースセグメントを見つける過程で重要な役割を果たします。二:cobarcelientのMysdalSql MapClint Templateはどうやってルータの対象SimpleRouterを使って分庫を実現しますか?
1.プロファイルの構成はどうなりますか?
classpath:ibatis/sqlmap-config.xml
classpath*:/ibatis/sqlmap/*.xml
classpath*:/ibatis/sqlmap/*/*-sqlmap.xml
2.Sql MapClint Templateは、IbatisのSql MapClint TemplateにパッケージしたMysdalSql MapClint Templateを構成から見ることができます。ソースコードを見てみます。元のSql MapClient Templateにはどのようなパッケージが作られていますか?public class MysdalSqlMapClientTemplate extends SqlMapClientTemplate implements DisposableBean {
// SqlMapClientTemplate , SqlMapClientTemplate
protected Map CURRENT_THREAD_SQLMAP_CLIENT_TEMPLATES = new HashMap();
private Set shards;
// SimpleRouter
private Router router;
private long timeout = 5000L;
private boolean useDefaultExecutor = false;
private ExecutorService executor = Executors.newFixedThreadPool(20);
public MysdalSqlMapClientTemplate() {
}
// CURRENT_THREAD_SQLMAP_CLIENT_TEMPLATES。
public void afterPropertiesSet() {
super.afterPropertiesSet();
if (this.shards != null && !this.shards.isEmpty()) {
if (this.router == null) {
throw new IllegalArgumentException("'router' argument is required");
} else {
if (this.executor == null) {
this.useDefaultExecutor = true;
this.executor = Executors.newCachedThreadPool(new ThreadFactory() {
public Thread newThread(Runnable runnable) {
return new Thread(runnable, "MysdalSqlMapClientTemplate executor thread");
}
});
}
Iterator i$ = this.shards.iterator();
while(i$.hasNext()) {
Shard shard = (Shard)i$.next();
this.CURRENT_THREAD_SQLMAP_CLIENT_TEMPLATES.put(shard.getId(), new SqlMapClientTemplate(shard.getDataSource(), this.getSqlMapClient()));
}
}
} else {
throw new IllegalArgumentException("'shards' argument is required.");
}
}
public void destroy() throws Exception {
if (this.useDefaultExecutor) {
this.executor.shutdown();
}
}
public boolean isHasShard(String statementName, Object parameterObject) {
Set shards = this.getRouter().route(statementName, parameterObject);
return shards.size() == 1;
}
public List queryForList(final String statementName, final Object parameterObject) throws DataAccessException {
Set shards = this.getRouter().route(statementName, parameterObject);
if (shards.isEmpty()) {
return super.queryForList(statementName, parameterObject);
} else {
return shards.size() == 1 ? ((SqlMapClientTemplate)this.CURRENT_THREAD_SQLMAP_CLIENT_TEMPLATES.get(((Shard)shards.iterator().next()).getId())).queryForList(statementName, parameterObject) : this.queryForListBase(shards, new SqlMapClientCallback() {
public List doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
return executor.queryForList(statementName, parameterObject);
}
});
}
}
.............
}
三:MysdalBaseDaoは原生ibatisのSql MapClient DaoSupportにどのようなパッケージを作りましたか?また、どうやって自分でカプセル化したMysdalSql MapClient Templateを使って分庫を実現しますか?まず次のような関係図を見ます。ソースは以下の通りです。
1.
public class MysdalBaseDao extends MysdalCobarSqlMapClientDaoSupport {
@Resource(name = "sqlMapClient")
private SqlMapClient sqlMapClient;
private int defaultBatchSize = 1000;
public MysdalBaseDao() {
}
@PostConstruct
public void initSqlMapClient() {
super.setSqlMapClient(this.sqlMapClient);
}
.......
}
2.
public class MysdalCobarSqlMapClientDaoSupport extends BaseSqlMapClientDaoSupport {
public MysdalCobarSqlMapClientDaoSupport() {
}
public int batchInsert(String statementName, List> entities) throws DataAccessException {
if (CollectionUtils.isEmpty(entities)) {
return 0;
} else if (this.isPartitionBehaviorEnabled()) {
MysdalSqlMapClientTemplate template = (MysdalSqlMapClientTemplate)this.getSqlMapClientTemplate();
return template.isHasShard(statementName, entities.get(0)) ? template.batchInsert(statementName, entities) : super.batchInsert(statementName, entities);
} else {
return super.batchInsert(statementName, entities);
}
}
protected boolean isPartitionBehaviorEnabled() {
return this.getSqlMapClientTemplate() instanceof MysdalSqlMapClientTemplate;
}
....
}
3.
public class BaseSqlMapClientDaoSupport extends SqlMapClientDaoSupport {
@Autowired
private SqlMapClientTemplate sqlMapClientTemplate = new SqlMapClientTemplate();
public BaseSqlMapClientDaoSupport() {
}
@PostConstruct
public void init() {
this.setSqlMapClientTemplate(this.sqlMapClientTemplate);
}
}
4.
public abstract class SqlMapClientDaoSupport extends DaoSupport {
private SqlMapClientTemplate sqlMapClientTemplate = new SqlMapClientTemplate();
private boolean externalTemplate = false;
public SqlMapClientDaoSupport() {
}
public final void setDataSource(DataSource dataSource) {
if (!this.externalTemplate) {
this.sqlMapClientTemplate.setDataSource(dataSource);
}
}
public final DataSource getDataSource() {
return this.sqlMapClientTemplate.getDataSource();
}
public final void setSqlMapClient(SqlMapClient sqlMapClient) {
if (!this.externalTemplate) {
this.sqlMapClientTemplate.setSqlMapClient(sqlMapClient);
}
}
public final SqlMapClient getSqlMapClient() {
return this.sqlMapClientTemplate.getSqlMapClient();
}
public final void setSqlMapClientTemplate(SqlMapClientTemplate sqlMapClientTemplate) {
Assert.notNull(sqlMapClientTemplate, "SqlMapClientTemplate must not be null");
this.sqlMapClientTemplate = sqlMapClientTemplate;
this.externalTemplate = true;
}
public final SqlMapClientTemplate getSqlMapClientTemplate() {
return this.sqlMapClientTemplate;
}
protected final void checkDaoConfig() {
if (!this.externalTemplate) {
this.sqlMapClientTemplate.afterPropertiesSet();
}
}
}
4:総括1.co barculientは異なる分庫の同じ表のルートをサポートしています。同庫の分表ルートをサポートしていません。ソースの角度から分析します。データベースに対して分片配置をしただけです。簡単に言えば、システム全体のデータソースをまとめて管理しています。一つのデータソースはSql MapClintTemplateに対応しています。また相応のSql MapClient Templateを持ってsqlを実行して結果を返します。この細分化された粒度はシステムデータソース全体に対して切り分けされていますが、より細かい粒度の同じデータベースの下の表の切り分けは処理されていません。こちらはコードによって具体的に指定された表名来を通じて該当表にアクセスします。2.ルーティングルールファイルを配置せず、デフォルトでアクセスするデータソースはdataSourceです。Mysdal Sql MapClient Template自体はSql MapClient Templateであり、父のdata Source属性を継承しているので、それ自体が自分のデータソースであるdata SourceというdataSourceはデフォルトのMysdalSql MapClient Templateデータソースです。