📄 triggersample.java
字号:
/* Copyright (c) 2001-2005, The HSQL Development Group * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */// use the org.hsqldb.sample package here; but will be in your own package usuallypackage org.hsqldb.sample;import java.io.PrintWriter;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.SQLException;import java.sql.Statement;import org.hsqldb.Trace;import org.hsqldb.Trigger;import org.hsqldb.lib.StringUtil;// peterhudson@users 20020130 - patch 478657 by peterhudson - new class// fredt@users 20030727 - signature altered// boucherb@users 20040315 - sample updated/** * <P>Sample code for use of triggers in hsqldb. * * SQL to invoke is:<p> * CREATE TRIGGER triggerSample BEFORE|AFTER INSERT|UPDATE|DELETE * ON myTable [FOR EACH ROW] [QUEUE n] [NOWAIT] CALL "myPackage.trigClass"<br> * * This will create a thread that will wait for its firing event to occur; * when this happens, the trigger's thread runs the 'trigClass.fire' * Note that this is still in the same Java Virtual Machine as the * database, so make sure the fired method does not hang.<p> * * There is a queue of events waiting to be run by each trigger thread. * This is particularly useful for 'FOR EACH ROW' triggers, when a large * number of trigger events occur in rapid succession, without the trigger * thread getting a chance to run. If the queue becomes full, subsequent * additions to it cause the database engine to suspend awaiting space * in the queue. Take great care to avoid this situation if the trigger * action involves accessing the database, as deadlock will occur. * This can be avoided either by ensuring the QUEUE parameter makes a large * enough queue, or by using the NOWAIT parameter, which causes a new * trigger event to overwrite the most recent event in the queue. * The default queue size is 1024.<p> * * Ensure that "myPackage.trigClass" is present in the classpath which * you use to start hsql.<p> * * If the method wants to access the database, it must establish * a JDBC connection.<p> * * When the 'fire' method is called, it is passed the following arguments: <p> * * fire (int type, String trigName, String tabName, Object oldRow[], * Object[] newRow) <p> * * where 'type' is one of the values enumerated in the Trigger interface and * the 'oldRow'/'newRow' pair represents the rows acted on. The first * length - 1 array slots contain column values and the final slot contains * either null or the value of the internally assigned row identity, if * the concerned table has no primary key. The final slot must _never_ be * modified. <p> * * The mapping of row classes to database types is specified in * /doc/hsqlSyntax.html#Datatypes. <p> * * To be done:<p> * * <ol> * <li> Implement the "jdbc:default:connection: URL to provide transparent * and portable access to internal connections for use in triggers and * stored procedures. <p> * * <li> Implement declaritive column to trigger method argument * mapping, conditional execution (WHEN clause), etc. <p> * * <li> Investigate and refine synchronous and asynchronous trigger models. <p> * * Because certain combinations of trigger create parameters cause the * individual triggered actions of a multirow update to run in different * threads, it is possible for an 'after' trigger to run before its * corresponding 'before' trigger; the acceptability and implications * of this needs to be investigated, documented and the behaviour of * the engine fully specified. * * <li> Investigate and implement the SQL 200n specified execution stack under * arbitrary triggered action and SQL-invoked routine call graphs. * </ol> * * @author Peter Hudson * @author boucherb@users * @version 1.7.2 * @since 1.7.0 */public class TriggerSample implements Trigger { static final PrintWriter out = new PrintWriter(System.out); static final String drv = "org.hsqldb.jdbcDriver"; static final String url = "jdbc:hsqldb:mem:trigger-sample"; static final String usr = "sa"; static final String pwd = ""; static final String impl = TriggerSample.class.getName(); static final String tn = "trig_test"; static final String drop_test_table_stmt = "DROP TABLE " + tn + " IF EXISTS"; static final String create_test_table_stmt = "CREATE TABLE " + tn + "(id INTEGER PRIMARY KEY, value VARCHAR(20))"; static final String drop_audit_table_stmt = "DROP TABLE audit IF EXISTS"; static final String create_audit_table_stmt = "CREATE TABLE audit(" + "id INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1), " + "op VARCHAR(6), " + "tn VARCHAR, " + "ors LONGVARCHAR, " + "nrs LONGVARCHAR, " + "ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"; static final String audit_insert_stmt = "INSERT INTO audit(op, tn, ors, nrs) VALUES(?, ?, ?, ?)"; /** * A sample HSQLDB Trigger interface implementation. <p> * * This sample prints information about the firing trigger and records * actions in an audit table. <p> * * The techniques used here are simplified dramatically for demonstration * purposes and are in no way recommended as a model upon which to build * actual installations involving triggered actions. * * @param typ trigger type * @param trn trigger name * @param tn table name * @param or old row * @param nr new row */ public void fire(int typ, String trn, String tn, Object[] or, Object[] nr) { synchronized (TriggerSample.class) { String ors = or == null ? "null" : StringUtil.arrayToString(or); String nrs = nr == null ? "null" : StringUtil.arrayToString(nr); out.println("----------------------------------------"); out.println(getTriggerDescriptor(trn, typ, tn)); out.println("old row : " + ors); out.println("new row : " + nrs); out.flush(); if ("TRIG_TEST".equals(tn)) { switch (typ) { case INSERT_BEFORE_ROW : { // Business rule: ID shall be less than 11. // (Marti DiBergi, we love you ;-) // You can cast row[i] given your knowledge of what // the table format is: final int ID = ((Number) nr[0]).intValue(); doAssert(ID < 11, "ID < 11"); break; } case UPDATE_BEFORE_ROW : { // Business rule: ignore update of VALUE 'unchangable'. if ("unchangable".equals(or[1])) { nr[1] = or[1]; // short-circuit the update } // !!!Warning!!! // The engine does not check the class of substituted // values; it's up to you to use the correct class. // For example, this will cause database curruption: // nr[1] = new Integer(5); break; } } } doAuditStep(typ, tn, ors, nrs); } } private static void doAssert(boolean b, String msg) throws RuntimeException { if (b) { // do nothing } else { msg = Trace.getMessage(Trace.ASSERT_FAILED) + ": " + msg; throw new RuntimeException(msg); } } private static void doAuditStep(int typ, String tn, String ors, String nrs) { Connection conn; PreparedStatement stmt; switch (typ) { case INSERT_AFTER_ROW : case UPDATE_AFTER_ROW : case DELETE_AFTER_ROW : { try { conn = getConnection(); stmt = conn.prepareStatement(audit_insert_stmt); stmt.setString(1, getOperationSpec(typ)); stmt.setString(2, tn); stmt.setString(3, ors); stmt.setString(4, nrs); stmt.executeUpdate(); conn.close(); } catch (SQLException se) { se.printStackTrace(); } } } } public static String getWhenSpec(int type) { switch (type) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -