我们看看insert语句的执行过程,
如果cs.isTransactionStatement()是true,则表示启动事务执行,
public Result executeCompiledStatement(Statement cs, Object[] pvals) { Result r; if (abortTransaction) { rollback(false); return Result.newErrorResult(Error.error(ErrorCode.X_40001)); } if (sessionContext.depth > 0) { if (sessionContext.noSQL.booleanValue() || cs.isAutoCommitStatement()) { return Result.newErrorResult(Error.error(ErrorCode.X_46000)); } } if (cs.isAutoCommitStatement()) { if (isReadOnly()) { return Result.newErrorResult(Error.error(ErrorCode.X_25006)); } try { /** special autocommit for backward compatibility */ commit(false); } catch (HsqlException e) { database.logger.logInfoEvent("Exception at commit"); } } sessionContext.currentStatement = cs; boolean isTX = cs.isTransactionStatement(); if (!isTX) { if (database.logger.getSqlEventLogLevel() >= SimpleLog.LOG_NORMAL) { sessionContext.setDynamicArguments(pvals); database.logger.logStatementEvent(this, cs, pvals, SimpleLog.LOG_NORMAL); } r = cs.execute(this); sessionContext.currentStatement = null; return r; } while (true) { actionIndex = rowActionList.size(); database.txManager.beginAction(this, cs); cs = sessionContext.currentStatement; if (cs == null) { return Result.newErrorResult(Error.error(ErrorCode.X_07502)); } if (abortTransaction) { rollback(false); sessionContext.currentStatement = null; return Result.newErrorResult(Error.error(ErrorCode.X_40001)); } try { latch.await(); } catch (InterruptedException e) { abortTransaction = true; } if (abortTransaction) { rollback(false); sessionContext.currentStatement = null; return Result.newErrorResult(Error.error(ErrorCode.X_40001)); } database.txManager.beginActionResume(this); // tempActionHistory.add("sql execute " + cs.sql + " " + actionTimestamp + " " + rowActionList.size()); sessionContext.setDynamicArguments(pvals); if (database.logger.getSqlEventLogLevel() >= SimpleLog.LOG_NORMAL) { database.logger.logStatementEvent(this, cs, pvals, SimpleLog.LOG_NORMAL); } r = cs.execute(this); lockStatement = sessionContext.currentStatement; // tempActionHistory.add("sql execute end " + actionTimestamp + " " + rowActionList.size()); endAction(r); if (abortTransaction) { rollback(false); sessionContext.currentStatement = null; return Result.newErrorResult(Error.error(r.getException(), ErrorCode.X_40001, null)); } if (redoAction) { redoAction = false; try { latch.await(); } catch (InterruptedException e) { abortTransaction = true; } } else { break; } } if (sessionContext.depth == 0 && (sessionContext.isAutoCommit.booleanValue() || cs.isAutoCommitStatement())) { try { if (r.mode == ResultConstants.ERROR) { rollback(false); } else { commit(false); } } catch (Exception e) { sessionContext.currentStatement = null; return Result.newErrorResult(Error.error(ErrorCode.X_40001, e)); } } sessionContext.currentStatement = null; return r; }
database.txManager.beginAction(this, cs); 事务执行开始阶段, 这里事务处理用简单的方式进行处理,
事务处理有几种实现,MVCC,2PL两阶段提交,
/** * add session to the end of queue when a transaction starts * (depending on isolation mode) */ public void beginAction(Session session, Statement cs) { if (session.isTransaction) { return; } if (cs == null) { return; } writeLock.lock(); try { if (cs.getCompileTimestamp() < database.schemaManager.getSchemaChangeTimestamp()) { cs = session.statementManager.getStatement(session, cs); session.sessionContext.currentStatement = cs; if (cs == null) { return; } } session.isPreTransaction = true; if (!isLockedMode && !cs.isCatalogLock()) { return; } beginActionTPL(session, cs); } finally { writeLock.unlock(); } }
锁整个表其实就是在当前的TractionManager对象中保存每个表的session对象,也就是每个表操作的每个session对象,这样就是session当前操作需要对这个表加锁,有读锁,写锁。
void lockTablesTPL(Session session, Statement cs) { if (cs == null || session.abortTransaction) { return; } HsqlName[] nameList = cs.getTableNamesForWrite(); for (int i = 0; i < nameList.length; i++) { HsqlName name = nameList[i]; if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) { continue; } tableWriteLocks.put(name, session); } nameList = cs.getTableNamesForRead(); for (int i = 0; i < nameList.length; i++) { HsqlName name = nameList[i]; if (name.schema == SqlInvariants.SYSTEM_SCHEMA_HSQLNAME) { continue; } tableReadLocks.put(name, session); } }
执行过程 r = cs.execute(this);
中间主要部分是StatementInsert类的这个方法
Result getResult(Session session) { Result resultOut = null; RowSetNavigator generatedNavigator = null; PersistentStore store = baseTable.getRowStore(session); int count; if (generatedIndexes != null) { resultOut = Result.newUpdateCountResult(generatedResultMetaData, 0); generatedNavigator = resultOut.getChainedResult().getNavigator(); } if (isSimpleInsert) { Type[] colTypes = baseTable.getColumnTypes(); Object[] data = getInsertData(session, colTypes, insertExpression.nodes[0].nodes); return insertSingleRow(session, store, data); } RowSetNavigator newDataNavigator = queryExpression == null ? getInsertValuesNavigator(session) : getInsertSelectNavigator(session); count = newDataNavigator.getSize(); if (count > 0) { insertRowSet(session, generatedNavigator, newDataNavigator); } if (baseTable.triggerLists[Trigger.INSERT_AFTER].length > 0) { baseTable.fireTriggers(session, Trigger.INSERT_AFTER, newDataNavigator); } if (resultOut == null) { resultOut = new Result(ResultConstants.UPDATECOUNT, count); } else { resultOut.setUpdateCount(count); } if (count == 0) { session.addWarning(HsqlException.noDataCondition); } return resultOut; }
PersistentStore store = baseTable.getRowStore(session);就是获取这个表对应的内存存储
我们用的是内存数据库,则这里store是org.hsqldb.persist.RowStoreAVLMemory@681070这个对象,待会我们再分析,
终于来到 insertSingleRow插入一条记录操作了
好吧,插入一条记录没那么简单,需要触发触发器操作和外键约束检测
Result insertSingleRow(Session session, PersistentStore store, Object[] data) { if (baseTable.triggerLists[Trigger.INSERT_BEFORE_ROW].length > 0) { baseTable.fireTriggers(session, Trigger.INSERT_BEFORE_ROW, null, data, null); } baseTable.insertSingleRow(session, store, data, null); performIntegrityChecks(session, baseTable, null, data, null); if (session.database.isReferentialIntegrity()) { for (int i = 0, size = baseTable.fkConstraints.length; i < size; i++) { baseTable.fkConstraints[i].checkInsert(session, baseTable, data, true); } } if (baseTable.triggerLists[Trigger.INSERT_AFTER_ROW].length > 0) { baseTable.fireTriggers(session, Trigger.INSERT_AFTER_ROW, null, data, null); } if (baseTable.triggerLists[Trigger.INSERT_AFTER].length > 0) { baseTable.fireTriggers(session, Trigger.INSERT_AFTER, (RowSetNavigator) null); } return Result.updateOneResult; }
/** * Mid level method for inserting single rows. Performs constraint checks and * fires row level triggers. */ Row insertSingleRow(Session session, PersistentStore store, Object[] data, int[] changedCols) { if (identityColumn != -1) { setIdentityColumn(session, data); } if (hasGeneratedValues) { setGeneratedColumns(session, data); } if (hasDomainColumns || hasNotNullColumns) { enforceRowConstraints(session, data); } if (isView) { // may have domain column return null; } Row row = (Row) store.getNewCachedObject(session, data, true); session.addInsertAction(this, store, row, changedCols); return row; }
如果有递增列,则要处理加1操作
/** * If there is an identity column in the table, sets * the value and/or adjusts the identiy value for the table. */ protected void setIdentityColumn(Session session, Object[] data) { if (identityColumn != -1) { Number id = (Number) data[identityColumn]; if (identitySequence.getName() == null) { if (id == null) { id = (Number) identitySequence.getValueObject(); data[identityColumn] = id; } else { identitySequence.userUpdate(id.longValue()); } } else { if (id == null) { id = (Number) session.sessionData.getSequenceValue( identitySequence); data[identityColumn] = id; } } if (session != null) { session.setLastIdentity(id); } } }
setGeneratedColumns 处理有表达式的列数据生成规则,
public void setGeneratedColumns(Session session, Object[] data) { if (hasGeneratedValues) { for (int i = 0; i < colGenerated.length; i++) { if (colGenerated[i]) { Expression e = getColumn(i).getGeneratingExpression(); RangeIteratorBase range = session.sessionContext.getCheckIterator( getDefaultRanges()[0]); range.currentData = data; data[i] = e.getValue(session, colTypes[i]); } } } }
enforceRowConstraints(session, data); 处理列的约束,如果整数是否超过限制等
/** * Enforce max field sizes according to SQL column definition. * SQL92 13.8 */ public void enforceRowConstraints(Session session, Object[] data) { for (int i = 0; i < columnCount; i++) { Type type = colTypes[i]; ColumnSchema column; if (hasDomainColumns && type.isDomainType()) { Constraint[] constraints = type.userTypeModifier.getConstraints(); column = getColumn(i); for (int j = 0; j < constraints.length; j++) { constraints[j].checkCheckConstraint(session, this, column, (Object) data[i]); } } if (colNotNull[i] && data[i] == null) { String constraintName; Constraint c = getNotNullConstraintForColumn(i); if (c == null) { if (ArrayUtil.find(this.primaryKeyCols, i) > -1) { c = this.getPrimaryConstraint(); } } constraintName = c == null ? "" : c.getName().name; column = getColumn(i); String[] info = new String[] { constraintName, tableName.statementName, column.getName().statementName }; throw Error.error(null, ErrorCode.X_23502, ErrorCode.COLUMN_CONSTRAINT, info); } } }
Row row = (Row) store.getNewCachedObject(session, data, true); 申请内存空间
public CachedObject getNewCachedObject(Session session, Object object, boolean tx) { int id; synchronized (this) { id = rowIdSequence++; } Row row = new RowAVL(table, (Object[]) object, id, this); if (tx) { RowAction action = new RowAction(session, table, RowAction.ACTION_INSERT, row, null); row.rowAction = action; } return row; }
RowAction action = new RowAction(session, table,
RowAction.ACTION_INSERT, row,
null);
表操作Represents the chain of insert / delete / rollback / commit actions on a row.
插入之前做的事情太多了,session.addInsertAction(this, store, row, changedCols); 终于来到操作插入的过程了。
public void addInsertAction(Session session, Table table, PersistentStore store, Row row, int[] changedColumns) { RowAction action = row.rowAction; if (action == null) { /* System.out.println("null insert action " + session + " " + session.actionTimestamp); */ throw Error.runtimeError(ErrorCode.GENERAL_ERROR, "null insert action "); } store.indexRow(session, row); session.rowActionList.add(action); row.rowAction = null; }
用AVL tree保存表的数据信息,索引而且每个节点保存数据,普通的AVL数操作,插入过程还加了写锁
/** * Insert a node into the index */ public void insert(Session session, PersistentStore store, Row row) { NodeAVL n; NodeAVL x; boolean isleft = true; int compare = -1; final Object[] rowData = row.getData(); boolean compareRowId = !isUnique || hasNulls(session, rowData); boolean compareSimple = isSimple; writeLock.lock(); try { n = getAccessor(store); x = n; if (n == null) { store.setAccessor(this, ((RowAVL) row).getNode(position)); return; } while (true) { Row currentRow = n.row; compare = 0; if (compareSimple) { compare = colTypes[0].compare(session, rowData[colIndex[0]], currentRow.getData()[colIndex[0]]); if (compare == 0 && compareRowId) { compare = compareRowForInsertOrDelete(session, row, currentRow, compareRowId, 1); } } else { compare = compareRowForInsertOrDelete(session, row, currentRow, compareRowId, 0); } // after the first match and check, all compares are with row id if (compare == 0 && session != null && !compareRowId && session.database.txManager.isMVRows()) { if (!isEqualReadable(session, store, n)) { compareRowId = true; compare = compareRowForInsertOrDelete(session, row, currentRow, compareRowId, colIndex.length); } } if (compare == 0) { if (isConstraint) { Constraint c = ((Table) table).getUniqueConstraintForIndex(this); throw c.getException(row.getData()); } else { throw Error.error(ErrorCode.X_23505, name.statementName); } } isleft = compare < 0; x = n; n = isleft ? x.nLeft : x.nRight; if (n == null) { break; } } x = x.set(store, isleft, ((RowAVL) row).getNode(position)); balance(store, x, isleft); } finally { writeLock.unlock(); } }
/** * Balances part of the tree after an alteration to the index. */ void balance(PersistentStore store, NodeAVL x, boolean isleft) { while (true) { int sign = isleft ? 1 : -1; switch (x.iBalance * sign) { case 1 : x.iBalance = 0; return; case 0 : x.iBalance = -sign; break; case -1 : NodeAVL l = isleft ? x.nLeft : x.nRight; if (l.iBalance == -sign) { x.replace(store, this, l); x.set(store, isleft, l.child(store, !isleft)); l.set(store, !isleft, x); x.iBalance = 0; l.iBalance = 0; } else { NodeAVL r = !isleft ? l.nLeft : l.nRight; x.replace(store, this, r); l.set(store, !isleft, r.child(store, isleft)); r.set(store, isleft, l); x.set(store, isleft, r.child(store, !isleft)); r.set(store, !isleft, x); int rb = r.iBalance; x.iBalance = (rb == -sign) ? sign : 0; l.iBalance = (rb == sign) ? -sign : 0; r.iBalance = 0; } return; } if (x.nParent == null) { return; } isleft = x.nParent == null || x == x.nParent.nLeft; x = x.nParent; } }
我们看下数据,当前有两条记录的数据
执行完之后 endAction(r); 事务处理结束,出错则回滚,成功则提交
public void endAction(Result result) { // tempActionHistory.add("endAction " + actionTimestamp); sessionData.persistentStoreCollection.clearStatementTables(); if (result.mode == ResultConstants.ERROR) { sessionData.persistentStoreCollection.clearResultTables( actionTimestamp); database.txManager.rollbackAction(this); } else { sessionContext .diagnosticsVariables[ExpressionColumn.idx_row_count] = result.mode == ResultConstants.UPDATECOUNT ? Integer.valueOf(result.getUpdateCount()) : ValuePool.INTEGER_0; database.txManager.completeActions(this); } // tempActionHistory.add("endAction ends " + actionTimestamp); }
成功的话当前就是清楚transationManager保存的session需要加锁的表信息了
void endActionTPL(Session session) { if (session.isolationLevel == SessionInterface.TX_REPEATABLE_READ || session.isolationLevel == SessionInterface.TX_SERIALIZABLE) { return; } if (session.sessionContext.currentStatement == null) { // after java function / proc with db access return; } if (session.sessionContext.depth > 0) { // routine or trigger return; } HsqlName[] readLocks = session.sessionContext.currentStatement.getTableNamesForRead(); if (readLocks.length == 0) { return; } writeLock.lock(); try { unlockReadTablesTPL(session, readLocks); final int waitingCount = session.waitingSessions.size(); if (waitingCount == 0) { return; } boolean canUnlock = false; // if write lock was used for read lock for (int i = 0; i < readLocks.length; i++) { if (tableWriteLocks.get(readLocks[i]) != session) { canUnlock = true; break; } } if (!canUnlock) { return; } canUnlock = false; for (int i = 0; i < waitingCount; i++) { Session current = (Session) session.waitingSessions.get(i); if (current.abortTransaction) { canUnlock = true; break; } Statement currentStatement = current.sessionContext.currentStatement; if (currentStatement == null) { canUnlock = true; break; } if (ArrayUtil.containsAny( readLocks, currentStatement.getTableNamesForWrite())) { canUnlock = true; break; } } if (!canUnlock) { return; } resetLocks(session); resetLatchesMidTransaction(session); } finally { writeLock.unlock(); } }
相关推荐
HSQLDB(HyperSQL Database)是一个轻量级、高性能的关系型数据库引擎,常用于Java应用程序和测试环境中。它的缓存机制和数据存储方式对于理解其性能和操作至关重要。以下是对HSQLDB的缓存分析和调试步骤的详细解释...
由于HSQLDB是开源的,开发者可以深入研究其源码,理解数据库的内部工作原理,如查询解析、执行计划生成、事务管理等,这对提升数据库相关的技术能力非常有帮助。 总之,HSQLDB作为一个轻量级、高性能的数据库,广泛...
3. **高性能**:HSQldb在处理大量数据时表现出良好的性能,得益于其高效的查询引擎和内存管理机制。 4. **支持SQL标准**:HSQldb兼容大部分SQL92和SQL99标准,提供丰富的SQL语句支持。 5. **嵌入式数据库**:...
3. **HSQldb管理工具** HSQldb自带的管理工具是`DatabaseManagerSwing`(还有`DatabaseManager`),它是一个基于Swing的GUI工具,可以用来管理HSQldb数据库。通过JDBC连接到运行在Server模式下的HSQldb,可以创建、...
src:HSQLDB数据库的最新源代码,在源代码中附加了轻松分析理解代码的注释 把代码引入Eclipse 运行mvn eclipse:eclipse生成Eclipse项目,打开Eclipse,选择File-> Import-> Existing Projects into Workspace 运行...
主要的类包括`org.hsqldb.Server`(服务器进程)、`org.hsqldb.jdbc.JDBCConnection`(JDBC连接)以及`org.hsqldb.Statement`(SQL语句执行)等。 ### 工具集成 HSQLDB常被用作开发和测试环境中的数据库,因为它...
《HSQLDB 1.8.0:轻量级数据库引擎的深度剖析》 HSQLDB,全称为HyperSQL Database,是一款开源、轻量级、高性能的关系型数据库管理系统,广泛应用于嵌入式系统和测试环境。HSQLDB 1.8.0是该数据库引擎的一个重要...
4. **插入数据**:使用`PreparedStatement`执行`INSERT INTO`语句,将数据插入到表中。 5. **关闭资源**:操作完成后,记得关闭`Statement`、`Connection`等资源,以释放系统资源。 接下来,我们讨论如何使用HSQldb...
- **约束和索引**:详细阐述了如何在HSQLDB中定义和使用主键、唯一性约束、唯一性索引以及外键约束,并分析了这些约束和索引如何影响查询性能。 - **类型和算术操作**:介绍了HSQLDB支持的各种数据类型,包括整型、...
**HSQLDB简介** HSQLDB(HyperSQL Database)是一个开源、轻量级、高性能的关系型数据库管理系统,适用于...了解并掌握HSQLDB的安装、使用和源码分析,能帮助开发者更好地理解和应用关系型数据库技术,提升项目效率。
3. 数据库操作:连接成功后,用户可以执行SQL语句,创建表、插入数据、查询数据、更新数据和删除数据。HSQldb支持大部分标准SQL语法,同时也有自己的特有功能,如内存数据库模式和文件数据库模式。 4. 管理与维护:...
《HSQldb 2.3.3:轻量级数据库引擎深度解析》 HSQldb,全称为HyperSQL Database,是一款开源、纯Java语言编写的轻量级关系型数据库管理系统,广泛应用于测试环境、嵌入式系统以及小型应用中。HSQldb 2.3.3是其稳定...
在性能方面,HSQldb以其小巧的体积和快速的执行速度著称。由于它可以完全基于内存运行,对于需要快速读写大量数据的应用来说,HSQldb是一个理想的选择。此外,HSQldb也支持磁盘存储,以满足更大型或持久性的数据存储...
**源码分析** HSQLDB是用Java编写的,因此其源码可读性较高,对于学习数据库原理和实现有很高的价值。通过阅读源码,开发者可以深入理解SQL的执行流程、事务管理、索引构建等核心概念。 **工具支持** HSQLDB提供...
3. **存储引擎**:HSQldb提供了内存存储和磁盘存储两种方式,内存存储适合小型应用,磁盘存储则适用于大型数据集。 4. **强大的查询能力**:HSQldb支持复杂的SQL查询,包括子查询、联接操作、视图等。 5. **自动备份...
3. 高性能:HSQLDB采用优化的查询引擎,能快速处理大量数据,提供高效的读写性能。 4. SQL兼容性:HSQLDB支持SQL:2008标准,提供丰富的SQL语句支持,包括事务、索引、视图、存储过程等。 5. 多种模式:HSQLDB支持单...
6. **触发器与存储过程**:HSQldb 支持创建触发器和存储过程,扩展了数据库的功能。 7. **Unicode支持**:HSQldb 全面支持Unicode字符集,满足多语言需求。 **HSQldb 示例** 在"hsqldb demo"中,可能包含了一个...
3. **内存数据库**:HSQldb可以作为内存数据库运行,这意味着数据存储在内存中,启动速度快,适用于临时数据存储或测试环境。 4. **文件数据库**:除了内存模式,HSQldb还可以将数据存储在磁盘文件中,适合于长期...
5. 其他工具:HSQldb可能包含一些用于数据导入/导出、数据库管理或性能分析的工具,这些工具可能依赖于额外的JAR文件。 使用这些额外的JAR文件时,我们需要确保它们与HSQldb的核心库以及其他依赖库兼容。通常,我们...