com.github.drinkjava2.jsqlbox.DbContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsqlbox Show documentation
Show all versions of jsqlbox Show documentation
jSqlBox is a full function DAO tool
/*
* Copyright 2016 the original author or authors.
*
* 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.github.drinkjava2.jsqlbox;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.sql.DataSource;
import com.github.drinkjava2.jdbpro.DbPro;
import com.github.drinkjava2.jdbpro.DbProException;
import com.github.drinkjava2.jdbpro.PreparedSQL;
import com.github.drinkjava2.jdbpro.SqlHandler;
import com.github.drinkjava2.jdbpro.SqlItem;
import com.github.drinkjava2.jdbpro.SqlOption;
import com.github.drinkjava2.jdbpro.template.BasicSqlTemplate;
import com.github.drinkjava2.jdialects.Dialect;
import com.github.drinkjava2.jdialects.TableModelUtils;
import com.github.drinkjava2.jdialects.TableModelUtilsOfDb;
import com.github.drinkjava2.jdialects.id.SnowflakeCreator;
import com.github.drinkjava2.jdialects.model.TableModel;
import com.github.drinkjava2.jsqlbox.entitynet.EntityNet;
import com.github.drinkjava2.jsqlbox.gtx.GtxConnectionManager;
import com.github.drinkjava2.jsqlbox.gtx.GtxInfo;
import com.github.drinkjava2.jsqlbox.gtx.GtxUtils;
import com.github.drinkjava2.jsqlbox.handler.EntityListHandler;
import com.github.drinkjava2.jsqlbox.handler.EntityNetHandler;
import com.github.drinkjava2.jsqlbox.sharding.ShardingModTool;
import com.github.drinkjava2.jsqlbox.sharding.ShardingRangeTool;
import com.github.drinkjava2.jsqlbox.sharding.ShardingTool;
import com.github.drinkjava2.jtransactions.tinytx.TinyTxConnectionManager;
/**
* DbContext is extended from DbPro, DbPro is extended from QueryRunner, by
* this way DbContext have all JDBC methods of QueryRunner and DbPro.
*
* As a ORM tool, DbContext focus on ORM methods like entity bean's CRUD
* methods and EntityNet methods.
*
* @author Yong Zhu
* @since 1.0.0
*/
@SuppressWarnings("unchecked")
public class DbContext extends DbPro {// NOSONAR
protected static ShardingTool[] globalNextShardingTools = new ShardingTool[] { new ShardingModTool(),
new ShardingRangeTool() };
protected static SnowflakeCreator globalNextSnowflakeCreator = null;
protected static Object[] globalNextSsModels = null;
public static final String NO_GLOBAL_SQLBOXCONTEXT_FOUND = "No default global DbContext found, need use method DbContext.setGlobalDbContext() to set a global default DbContext instance at the beginning of appication.";
protected static DbContext globalDbContext = new DbContext(); // this is a empty ctx
protected ShardingTool[] shardingTools = globalNextShardingTools;
protected SnowflakeCreator snowflakeCreator = globalNextSnowflakeCreator;
protected TableModel[] tailModels; // TableModels loaded from DB, only used for tail mode
public DbContext() {
super();
}
public DbContext(DataSource ds) {
super(ds);
}
public DbContext(DataSource ds, Dialect dialect) {
super(ds, dialect);
}
// ==========================Global Transaction about================
/** If current GlobalTxCM opened global Transaction */
public boolean isGtxOpen() {
return connectionManager instanceof GtxConnectionManager
&& getGtxManager().isInTransaction();
}
/** Get current GtxLockId, should be called inside of a global transaction */
public GtxInfo getGtxInfo() {
return (GtxInfo) getGtxManager().getThreadTxInfo();
}
/** Get current ConnectionManager and assume it's a GlobalTxCM */
public GtxConnectionManager getGtxManager() {
return (GtxConnectionManager) connectionManager;
}
// ==========================end=============
protected void miscMethods______________________________() {// NOSONAR
}
/** Reset all global SqlBox variants to default values */
public static void resetGlobalVariants() {
setGlobalNextAllowShowSql(false);
setGlobalNextMasterSlaveOption(SqlOption.USE_AUTO);
setGlobalNextConnectionManager(TinyTxConnectionManager.instance());
setGlobalNextSqlHandlers((SqlHandler[]) null);
setGlobalNextBatchSize(300);
setGlobalNextTemplateEngine(BasicSqlTemplate.instance());
setGlobalNextDialect(null);
setGlobalNextShardingTools(new ShardingTool[] { new ShardingModTool(), new ShardingRangeTool() });
globalDbContext = new DbContext();
}
/** Shortcut method equal to getGlobalDbContext() */
public static DbContext gctx() {
return DbContext.globalDbContext;
}
/** Get the global static DbContext instance */
public static DbContext getGlobalDbContext() {
return DbContext.globalDbContext;
}
/**
* Override DbPro's dealOneSqlItem method to deal DbContext's SqlItem
*/
@Override
protected boolean dealOneSqlItem(boolean iXxxStyle, PreparedSQL ps, Object item) {// NOSONAR
if (super.dealOneSqlItem(iXxxStyle, ps, item))
return true; // if super class DbPro can deal it, let it do
if (item instanceof SqlOption) {
if (SqlOption.IGNORE_NULL.equals(item))
ps.setIgnoreNull(true);
else if (SqlOption.AUTO_SQL.equals(item))
DbContextUtils.appendLeftJoinSQL(ps);
else
return false;
} else if (item instanceof TableModel) {
ps.addModel(item);
DbContextUtils.createLastAutoAliasName(ps);
} else if (item instanceof Class) {
ps.addModel(TableModelUtils.entity2ReadOnlyModel((Class>) item));
DbContextUtils.createLastAutoAliasName(ps);
return true;
} else if (item instanceof SqlItem) {
SqlItem sqItem = (SqlItem) item;
SqlOption sqlItemType = sqItem.getType();
if (SqlOption.SHARD_TABLE.equals(sqlItemType))
handleShardTable(ps, sqItem);
else if (SqlOption.SHARD_DATABASE.equals(sqlItemType))
handleShardDatabase(ps, sqItem);
else if (SqlOption.GIVE.equals(sqlItemType)) {
Object[] o = ((SqlItem) item).getParameters();
String[] s = new String[o.length];
for (int i = 0; i < o.length; i++)
s[i] = (String) o[i];
ps.addGives(s);
} else if (SqlOption.GIVE_BOTH.equals(sqlItemType)) {
Object[] a = ((SqlItem) item).getParameters();
ps.addGives(new String[] { (String) a[0], (String) a[1] });
ps.addGives(new String[] { (String) a[1], (String) a[0] });
} else if (SqlOption.ALIAS.equals(sqlItemType)) {
if (sqItem.getParameters().length == 0)
throw new DbException("alias method need parameter");
ps.setLastAliases((String[]) sqItem.getParameters());// NOSONAR
} else if (SqlOption.TAIL.equals(sqlItemType)) {
return true; // do nothing
} else
return false;
} else if (item instanceof EntityNet) {
ps.setEntityNet((EntityNet) item);
ps.addHandler(new EntityNetHandler());
} else
return false;
return true;
}
/** Get the sharded table name by given shard values */
public String getShardedTB(Object entityOrClass, Object... shardvalues) {
String table = DbContextUtils.getShardedTB(this, entityOrClass, shardvalues);
if (table == null)
throw new DbException("No found ShardingTool can handle target '" + entityOrClass + "' ");
return table;
}
/** Get the sharded DB(=DbContext) instance by given shard values */
public DbContext getShardedDB(Object entityOrClass, Object... shardvalues) {
DbContext ctx = DbContextUtils.getShardedDB(this, entityOrClass, shardvalues);
if (ctx == null)
throw new DbException("Not found ShardingTool can handle entity '" + entityOrClass + "' ");
return ctx;
}
protected String handleShardTable(PreparedSQL predSQL, SqlItem item) {
Object[] params = item.getParameters();
String table = null;
if (predSQL.getModels() == null || predSQL.getModels().length == 0)
throw new DbException("ShardTable not found model setting");
TableModel model = (TableModel) predSQL.getModels()[0];
if (params.length == 1)
table = DbContextUtils.getShardedTB(this, model, params[0]);
else if (params.length == 2)
table = DbContextUtils.getShardedTB(this, model, params[0], params[1]);
else
throw new DbException("ShardTable need 1 or 2 parameters");
if (table == null)
throw new DbException("No ShardTable Tool found.");
else
predSQL.addSql(table);
return table;
}
protected DbPro handleShardDatabase(PreparedSQL predSQL, SqlItem item) {
Object[] params = item.getParameters();
DbContext ctx = null;
if (predSQL.getModels() == null || predSQL.getModels().length == 0)
return this;
TableModel model = (TableModel) predSQL.getModels()[0];
if (params.length == 1)
ctx = DbContextUtils.getShardedDB(this, model, params[0]);
else if (params.length == 2)
ctx = DbContextUtils.getShardedDB(this, model, params[0], params[1]);
else
throw new DbException("ShardDatabase need 1 or 2 parameters");
if (ctx == null)
throw new DbException("No ShardDatabase Tool found.");
else
predSQL.setSwitchTo(ctx);
return ctx;
}
private static void checkOnlyOneRowAffected(int result, String curdType) {
if (result <= 0)
throw new DbException("No record found in database when do '" + curdType + "' operation.");
if (result > 1)
throw new DbException(
"Affect more than 1 row record in database when do '" + curdType + "' operation.");
}
/** Use i style to query for an entity list */
public List iQueryForEntityList(Object... optionItems) {
return this.iQuery(new EntityListHandler(), optionItems);
}
/** Use p style to query for an entity list */
public List pQueryForEntityList(Object... optionItems) {
return this.pQuery(new EntityListHandler(), optionItems);
}
/** Use t style to query for an entity list */
public List tQueryForEntityList(Object... optionItems) {
return this.tQuery(new EntityListHandler(), optionItems);
}
/** Build a entityNet, only give both between start class and end classes */
public EntityNet autoNet(Class>... entityClass) {
return DbContextUtils.entityAutoNet(this, entityClass);
}
/** If dbModels not loaded, loaded from database */
public void ensureTailModelLoaded() {
if (tailModels != null)
return;
reloadTailModels();
}
/** Start a transaction on a given locker server */
public void startTransOnLockDb(int lockDb) {
this.getConnectionManager().startTransaction();
GtxConnectionManager gcm = (GtxConnectionManager) this.getConnectionManager();
GtxInfo gtxInfo = (GtxInfo) gcm.getThreadTxInfo();
gtxInfo.setLockDb(lockDb);
}
/**
* Manually call this method to reload tail TableModels when database structure
* be changed by DDL command
*/
public synchronized void reloadTailModels() {
DataSource ds = getDataSource();
DbException.assureNotNull(ds, "Can not load tail TableModels when datasource is null");
Connection conn = null;
try {
conn = getDataSource().getConnection();
tailModels = TableModelUtilsOfDb.db2Models(conn, dialect);
} catch (SQLException e) {
throw new DbException(e);
} finally {
if (conn != null)
try {
conn.close();
} catch (SQLException e) {
DbException.eatException(e);
}
}
}
protected void entityCrudMethods______________________________() {// NOSONAR
}
/** Insert entity to database, if not 1 row updated, throw SqlBoxException */
public T eInsert(T entity, Object... optionItems) {
int result = DbContextUtils.entityInsertTry(this, entity, optionItems);
checkOnlyOneRowAffected(result, "insert");
return entity;
}
/** Update entity in database, if not 1 row updated, throw SqlBoxException */
public T eUpdate(Object entity, Object... optionItems) {
int result = DbContextUtils.entityUpdateTry(this, entity, optionItems);
checkOnlyOneRowAffected(result, "update");
return (T) entity;
}
/** Update entity in database, return how many rows affected */
public int eUpdateTry(Object entity, Object... optionItems) {
return DbContextUtils.entityUpdateTry(this, entity, optionItems);
}
/** Delete entity in database, if not 1 row deleted, throw SqlBoxException */
public void eDelete(Object entity, Object... optionItems) {
int result = DbContextUtils.entityDeleteTry(this, entity, optionItems);
checkOnlyOneRowAffected(result, "delete");
}
/** Delete entity in database, return how many rows affected */
public int eDeleteTry(Object entity, Object... optionItems) {
return DbContextUtils.entityDeleteTry(this, entity, optionItems);
}
/** Delete entity by given id, if not 1 row deleted, throw SqlBoxException */
public void eDeleteById(Class> entityClass, Object id, Object... optionItems) {
int result = DbContextUtils.entityDeleteByIdTry(this, entityClass, id, optionItems);
checkOnlyOneRowAffected(result, "deleteById");
}
/** Delete entity by given id, return how many rows deleted */
public int eDeleteByIdTry(Class> entityClass, Object id, Object... optionItems) {
return DbContextUtils.entityDeleteByIdTry(this, entityClass, id, optionItems);
}
/** Check if entity exist by its id */
public boolean eExistStrict(Object entity, Object... optionItems) {
return DbContextUtils.entityExistStrict(this, entity, optionItems);
}
/** Check if entity exist by its id */
public boolean eExist(Object entity, Object... optionItems) {
return DbContextUtils.entityExist(this, entity, optionItems);
}
/** Check if entity exist by given id */
public boolean eExistById(Class> entityClass, Object id, Object... optionItems) {
return DbContextUtils.entityExistById(this, entityClass, id, optionItems);
}
/** Return how many records for current entity class */
public int eCountAll(Class> entityClass, Object... optionItems) {
return DbContextUtils.entityCountAll(this, entityClass, optionItems);
}
/** Load entity according its id, if not 1 row round, throw SqlBoxException */
public T eLoad(T entity, Object... optionItems) {
int result = DbContextUtils.entityLoadTry(this, entity, optionItems);
checkOnlyOneRowAffected(result, "load");
return entity;
}
/** Load entity according its id, return how many rows found */
public int eLoadTry(Object entity, Object... optionItems) {
return DbContextUtils.entityLoadTry(this, entity, optionItems);
}
/** Load entity by given id, if not 1 row found, throw SqlBoxException */
public T eLoadById(Class entityClass, Object entityId, Object... optionItems) {
T entity = DbContextUtils.entityLoadByIdTry(this, entityClass, entityId, optionItems);
if (entity == null)
throw new DbException("No record found in database when do 'LoadById' operation.");
return entity;
}
/** Load one entity according SQL, if not found, return null */
public T eLoadBySQL(Object... optionItems) {
List entities = iQueryForEntityList(optionItems);
if (entities == null || entities.isEmpty())
throw new DbException("No record found in database when try to load entity.");
if (entities.size() > 1)
throw new DbException("More than 1 record found when try to load 1 entity.");
return entities.get(0);
}
/** Load entity by given id, if not found, return null */
public T eLoadByIdTry(Class entityClass, Object entityId, Object... optionItems) {
return DbContextUtils.entityLoadByIdTry(this, entityClass, entityId, optionItems);
}
/**
* Find all entity of given entity class as List, if not found, return empty
* list
*/
public List eFindAll(Class entityClass, Object... optionItems) {
return DbContextUtils.entityFindAll(this, entityClass, optionItems);
}
/**
* Find entity according SQL, entityClass usually is first param, if not found,
* return empty list
*/
public List eFindBySQL(Object... optionItems) {
return iQueryForEntityList(optionItems);
}
/**
* Find entity according a sample bean, ignore null fields, if not found, return
* empty list
*/
public List eFindBySample(Object sampleBean, Object... optionItems) {
return DbContextUtils.entityFindBySample(this, sampleBean, optionItems);
}
/** Find one related entity by given entity */
public E eFindRelatedOne(Object entity, Object... sqlItems) {
return DbContextUtils.entityFindRelatedOne(this, entity, sqlItems);
}
/** Find related entity list by given entity or Iterable */
public List eFindRelatedList(Object entityOrIterable, Object... sqlItems) {
return DbContextUtils.entityFindRelatedList(this, entityOrIterable, sqlItems);
}
/** Find related entity set by given entity or Iterable */
public Set eFindRelatedSet(Object entity, Object... sqlItems) {
return DbContextUtils.entityFindRelatedSet(this, entity, sqlItems);
}
/** Find related entity map(key is entityID) by given entity or Iterable */
public Map