精华内容
下载资源
问答
  • Java Connection rollBack()方法与示例
    2021-04-14 04:42:40

    回滚操作将撤消当前事务所做的所有更改,即,如果调用Connection接口的rollBack()方法,则所有修改都将还原到最后一次提交。

    您还可以通过将所需的Savepoint对象作为参数传递给此方法,将数据库中的更改回滚到特定的保存点,如下所示://Setting the save point

    con.rollback("MysavePoint");

    回滚事务

    使用DriverManager类的registerDriver()方法将驱动程序注册为-//注册驱动程序

    DriverManager.registerDriver(new com.mysql.jdbc.Driver());

    使用getConnection()DriverManager类的方法获取连接,如下所示://获得连接

    String url = "jdbc:mysql://localhost/mydatabase";

    Connection con = DriverManager.getConnection(url, "root", "password");

    使用setAutoCommit()方法关闭自动提交,如下所示://将自动提交设置为false-

    con.setAutoCommit(false);

    使用setSavepoint()设置保存点,或者使用以下commit()方法提交事务:Savepoint savePoint = con.setSavepoint("MysavePoint");

    Con.commit();

    最后,回滚到最后一个保存点,或者使用rollback()或rollback(Savepoint savepoint)方法最后提交。con.rollback()

    Or,

    con. rollback(mySavepoint);

    让我们使用CREATE语句在MySQL数据库中创建一个名为MyPlayers的表,如下所示-CREATE TABLE MyPlayers(

    ID INT,

    First_Name VARCHAR(255),

    Last_Name VARCHAR(255),

    Date_Of_Birth date,

    Place_Of_Birth VARCHAR(255),

    Country VARCHAR(255),

    PRIMARY KEY (ID)

    );

    现在,我们将使用INSERT语句在MyPlayers表中插入7条记录-insert into MyPlayers values(1, 'Shikhar', 'Dhawan', DATE('1981-12-05'), 'Delhi', 'India');

    insert into MyPlayers values(2, 'Jonathan', 'Trott', DATE('1981-04-22'), 'CapeTown', 'SouthAfrica');

    insert into MyPlayers values(3, 'Kumara', 'Sangakkara', DATE('1977-10-27'), 'Matale', 'Srilanka');

    insert into MyPlayers values(4, 'Virat', 'Kohli', DATE('1988-11-05'), 'Delhi', 'India');

    insert into MyPlayers values(5, 'Rohit', 'Sharma', DATE('1987-04-30'), 'Nagpur', 'India');

    insert into MyPlayers values(6, 'Ravindra', 'Jadeja', DATE('1988-12-06'), 'Nagpur', 'India');

    insert into MyPlayers values(7, 'James', 'Anderson', DATE('1982-06-30'), 'Burnley', 'England');

    以下JDBC程序演示了Connection接口的rollback()方法。在这里,我们在Myplayers表中插入了一条新记录。使用该commit()方法完成事务,删除先前插入的记录,然后回滚到创建的保存点,并显示表的内容

    示例import java.sql.Connection;

    import java.sql.Date;

    import java.sql.DriverManager;

    import java.sql.PreparedStatement;

    import java.sql.ResultSet;

    import java.sql.SQLException;

    import java.sql.Statement;

    public class Connection_rollBack {

    public static void main(String args[]) throws SQLException {

    //注册驱动程序

    DriverManager.registerDriver(new com.mysql.jdbc.Driver());

    //获得连接

    String url = "jdbc:mysql://localhost/mydatabase";

    Connection con = DriverManager.getConnection(url, "root", "password");

    System.out.println("Connection established......");

    //将自动提交设置为false-

    con.setAutoCommit(false);

    //创建一个Statement对象

    Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);

    //检索数据

    ResultSet rs = stmt.executeQuery("select * from MyPlayers");

    System.out.println("Contents of the table initially");

    while(rs.next()) {

    System.out.print("ID: "+rs.getString("ID")+", ");

    System.out.print("First_Name: "+rs.getString("First_Name")+", ");

    System.out.print("Last_Name: "+rs.getString("Last_Name")+", ");

    System.out.print("Date_Of_Birth: "+rs.getString("Date_Of_Birth")+", ");

    System.out.print("Place_Of_Birth: "+rs.getString("Place_Of_Birth")+", ");

    System.out.print("Country: "+rs.getString("Country"));

    System.out.println("");

    }

    PreparedStatement pstmt = con.prepareStatement("INSERT INTO MyPlayers VALUES (?, ?, ?, ?, ?, ?)");

    pstmt.setInt(1, 8);

    pstmt.setString(2, "Ishant");

    pstmt.setString(3, "Sharma");

    pstmt.setDate(4, new Date(904694400000L));

    pstmt.setString(5, "Delhi");

    pstmt.setString(6, "India");

    pstmt.executeUpdate();

    //提交事务

    con.commit();

    //删除记录

    stmt.execute("Delete from MyPlayers where id = 8");

    //回滚到保存点

    con.rollback();

    //回滚后表的内容

    System.out.println("Contents of the table");

    rs = stmt.executeQuery("select * from MyPlayers");

    while(rs.next()) {

    System.out.print("ID: "+rs.getString("ID")+", ");

    System.out.print("First_Name: "+rs.getString("First_Name")+", ");

    System.out.print("Last_Name: "+rs.getString("Last_Name")+", ");

    System.out.print("Date_Of_Birth: "+rs.getString("Date_Of_Birth")+", ");

    System.out.print("Place_Of_Birth: "+rs.getString("Place_Of_Birth")+", ");

    System.out.print("Country: "+rs.getString("Country"));

    System.out.println("");

    }

    }

    }

    现在,您可以观察结果中保存点之前创建的新记录,尽管我们已将其删除。

    如果我们回滚一个事务,那么在上一次提交之后所做的所有更改都将被还原。

    由于我们已在设置提交后删除了第8条记录,因此在回滚时将还原此删除。

    输出结果Connection established......

    Contents of the table initially

    ID: 1, First_Name: Shikhar, Last_Name: Dhawan, Date_Of_Birth: 1981-12-05, Place_Of_Birth: Delhi, Country: India

    ID: 2, First_Name: Jonathan, Last_Name: Trott, Date_Of_Birth: 1981-04-22, Place_Of_Birth: CapeTown, Country: SouthAfrica

    ID: 3, First_Name: Kumara, Last_Name: Sangakkara, Date_Of_Birth: 1977-10-27, Place_Of_Birth: Matale, Country: Srilanka

    ID: 4, First_Name: Virat, Last_Name: Kohli, Date_Of_Birth: 1988-11-05, Place_Of_Birth: Mumbai, Country: India

    ID: 5, First_Name: Rohit, Last_Name: Sharma, Date_Of_Birth: 1987-04-30, Place_Of_Birth: Nagpur, Country: India

    ID: 6, First_Name: Ravindra, Last_Name: Jadeja, Date_Of_Birth: 1988-12-06, Place_Of_Birth: Nagpur, Country: India

    ID: 7, First_Name: James, Last_Name: Anderson, Date_Of_Birth: 1982-06-30, Place_Of_Birth: Burnley , Country: England

    Contents of the table after rollback

    ID: 1, First_Name: Shikhar, Last_Name: Dhawan, Date_Of_Birth: 1981-12-05, Place_Of_Birth: Delhi, Country: India

    ID: 2, First_Name: Jonathan, Last_Name: Trott, Date_Of_Birth: 1981-04-22, Place_Of_Birth: CapeTown, Country: SouthAfrica

    ID: 3, First_Name: Kumara, Last_Name: Sangakkara, Date_Of_Birth: 1977-10-27, Place_Of_Birth: Matale, Country: Srilanka

    ID: 4, First_Name: Virat, Last_Name: Kohli, Date_Of_Birth: 1988-11-05, Place_Of_Birth: Mumbai, Country: India

    ID: 5, First_Name: Rohit, Last_Name: Sharma, Date_Of_Birth: 1987-04-30, Place_Of_Birth: Nagpur, Country: India

    ID: 6, First_Name: Ravindra, Last_Name: Jadeja, Date_Of_Birth: 1988-12-06, Place_Of_Birth: Nagpur, Country: India

    ID: 7, First_Name: James, Last_Name: Anderson, Date_Of_Birth: 1982-06-30, Place_Of_Birth: Burnley , Country: England

    ID: 8, First_Name: Ishant, Last_Name: Sharma, Date_Of_Birth: 1998-09-02, Place_Of_Birth: Delhi, Country: India

    更多相关内容
  • Sql Server 2005/2008中提供了begin tran,commit tran和rollback tran来使用事务。begin tran表示开始事务, commit tran表示提交事务,rollback tran表示回滚事物
  • RollBack Rx v11.1 正式永久使用无限制,内包括正式版本SN(注册码) 非破解版本。
  • mysql执行DDL语句的时候提示错误: [Err] 4644 – [1065507aa5d0c000][10.0.85.135:3306][test]ERR-CODE: [TDDL-4644][ERR_PENDING_DDL_JOB_EXISTS] Another DDL job ‘1181437929186181120’ with operation ...
  • Ansible-rollback.zip

    2019-09-18 09:40:41
    Ansible-rollback.zip,在capistrano styleansistrano中负责回滚脚本应用程序(如php、python、ruby等),ansible是一个简单而强大的自动化引擎。它用于帮助配置管理、应用程序部署和任务自动化。
  • Rollback

    2020-04-28 22:38:39
    Rollback Sometimes things don’t go as planned when attempting an upgrade. This section explains how to perform a rollback to an earlier HBase release. Note that this should only be needed between Ma...
    1. Rollback

    Sometimes things don’t go as planned when attempting an upgrade. This section explains how to perform a rollback to an earlier HBase release. Note that this should only be needed between Major and some Minor releases. You should always be able to downgrade between HBase Patch releases within the same Minor version. These instructions may require you to take steps before you start the upgrade process, so be sure to read through this section beforehand.
    12.1. Caveats
    Rollback vs Downgrade

    This section describes how to perform a rollback on an upgrade between HBase minor and major versions. In this document, rollback refers to the process of taking an upgraded cluster and restoring it to the old version while losing all changes that have occurred since upgrade. By contrast, a cluster downgrade would restore an upgraded cluster to the old version while maintaining any data written since the upgrade. We currently only offer instructions to rollback HBase clusters. Further, rollback only works when these instructions are followed prior to performing the upgrade.

    When these instructions talk about rollback vs downgrade of prerequisite cluster services (i.e. HDFS), you should treat leaving the service version the same as a degenerate case of downgrade.
    Replication

    Unless you are doing an all-service rollback, the HBase cluster will lose any configured peers for HBase replication. If your cluster is configured for HBase replication, then prior to following these instructions you should document all replication peers. After performing the rollback you should then add each documented peer back to the cluster. For more information on enabling HBase replication, listing peers, and adding a peer see Managing and Configuring Cluster Replication. Note also that data written to the cluster since the upgrade may or may not have already been replicated to any peers. Determining which, if any, peers have seen replication data as well as rolling back the data in those peers is out of the scope of this guide.
    Data Locality

    Unless you are doing an all-service rollback, going through a rollback procedure will likely destroy all locality for Region Servers. You should expect degraded performance until after the cluster has had time to go through compactions to restore data locality. Optionally, you can force a compaction to speed this process up at the cost of generating cluster load.
    Configurable Locations

    The instructions below assume default locations for the HBase data directory and the HBase znode. Both of these locations are configurable and you should verify the value used in your cluster before proceeding. In the event that you have a different value, just replace the default with the one found in your configuration * HBase data directory is configured via the key ‘hbase.rootdir’ and has a default value of ‘/hbase’. * HBase znode is configured via the key ‘zookeeper.znode.parent’ and has a default value of ‘/hbase’.
    12.2. All service rollback

    If you will be performing a rollback of both the HDFS and ZooKeeper services, then HBase’s data will be rolled back in the process.
    Requirements

    Ability to rollback HDFS and ZooKeeper
    

    Before upgrade

    No additional steps are needed pre-upgrade. As an extra precautionary measure, you may wish to use distcp to back up the HBase data off of the cluster to be upgraded. To do so, follow the steps in the ‘Before upgrade’ section of ‘Rollback after HDFS downgrade’ but copy to another HDFS instance instead of within the same instance.
    Performing a rollback

    Stop HBase
    
    Perform a rollback for HDFS and ZooKeeper (HBase should remain stopped)
    
    Change the installed version of HBase to the previous version
    
    Start HBase
    
    Verify HBase contents—use the HBase shell to list tables and scan some known values.
    

    12.3. Rollback after HDFS rollback and ZooKeeper downgrade

    If you will be rolling back HDFS but going through a ZooKeeper downgrade, then HBase will be in an inconsistent state. You must ensure the cluster is not started until you complete this process.
    Requirements

    Ability to rollback HDFS
    
    Ability to downgrade ZooKeeper
    

    Before upgrade

    No additional steps are needed pre-upgrade. As an extra precautionary measure, you may wish to use distcp to back up the HBase data off of the cluster to be upgraded. To do so, follow the steps in the ‘Before upgrade’ section of ‘Rollback after HDFS downgrade’ but copy to another HDFS instance instead of within the same instance.
    Performing a rollback

    Stop HBase
    
    Perform a rollback for HDFS and a downgrade for ZooKeeper (HBase should remain stopped)
    
    Change the installed version of HBase to the previous version
    
    Clean out ZooKeeper information related to HBase. WARNING: This step will permanently destroy all replication peers. Please see the section on HBase Replication under Caveats for more information.
    Clean HBase information out of ZooKeeper
    
    [hpnewton@gateway_node.example.com ~]$ zookeeper-client -server zookeeper1.example.com:2181,zookeeper2.example.com:2181,zookeeper3.example.com:2181
    Welcome to ZooKeeper!
    JLine support is disabled
    rmr /hbase
    quit
    Quitting...
    
    Start HBase
    
    Verify HBase contents—use the HBase shell to list tables and scan some known values.
    

    12.4. Rollback after HDFS downgrade

    If you will be performing an HDFS downgrade, then you’ll need to follow these instructions regardless of whether ZooKeeper goes through rollback, downgrade, or reinstallation.
    Requirements

    Ability to downgrade HDFS
    
    Pre-upgrade cluster must be able to run MapReduce jobs
    
    HDFS super user access
    
    Sufficient space in HDFS for at least two copies of the HBase data directory
    

    Before upgrade

    Before beginning the upgrade process, you must take a complete backup of HBase’s backing data. The following instructions cover backing up the data within the current HDFS instance. Alternatively, you can use the distcp command to copy the data to another HDFS cluster.

    Stop the HBase cluster
    
    Copy the HBase data directory to a backup location using the distcp command as the HDFS super user (shown below on a security enabled cluster)
    Using distcp to backup the HBase data directory
    
    [hpnewton@gateway_node.example.com ~]$ kinit -k -t hdfs.keytab hdfs@EXAMPLE.COM
    [hpnewton@gateway_node.example.com ~]$ hadoop distcp /hbase /hbase-pre-upgrade-backup
    
    Distcp will launch a mapreduce job to handle copying the files in a distributed fashion. Check the output of the distcp command to ensure this job completed successfully.
    

    Performing a rollback

    Stop HBase
    
    Perform a downgrade for HDFS and a downgrade/rollback for ZooKeeper (HBase should remain stopped)
    
    Change the installed version of HBase to the previous version
    
    Restore the HBase data directory from prior to the upgrade as the HDFS super user (shown below on a security enabled cluster). If you backed up your data on another HDFS cluster instead of locally, you will need to use the distcp command to copy it back to the current HDFS cluster.
    Restore the HBase data directory
    
    [hpnewton@gateway_node.example.com ~]$ kinit -k -t hdfs.keytab hdfs@EXAMPLE.COM
    [hpnewton@gateway_node.example.com ~]$ hdfs dfs -mv /hbase /hbase-upgrade-rollback
    [hpnewton@gateway_node.example.com ~]$ hdfs dfs -mv /hbase-pre-upgrade-backup /hbase
    
    Clean out ZooKeeper information related to HBase. WARNING: This step will permanently destroy all replication peers. Please see the section on HBase Replication under Caveats for more information.
    Clean HBase information out of ZooKeeper
    
    [hpnewton@gateway_node.example.com ~]$ zookeeper-client -server zookeeper1.example.com:2181,zookeeper2.example.com:2181,zookeeper3.example.com:2181
    Welcome to ZooKeeper!
    JLine support is disabled
    rmr /hbase
    quit
    Quitting...
    
    Start HBase
    
    Verify HBase contents–use the HBase shell to list tables and scan some known values.
    
    展开全文
  • 快照和回滚支持Linux发行版上的配置文件。 可以手动/定期/自动保存配置的工具。 用于查看存储文件中差异的工具以及用于还原它们的工具。
  • Android RollBack机制实现原理剖析

    千次阅读 2020-10-18 14:18:59
    这样的确可以极大的提升用户的体验,但是因为这块的逻辑较复杂,我们以module_crash_rollback_test为例,来看下具体的实现逻辑。 代码路径如下: ./base/services/core/java/com/android/server/rollback ./base/...

    功能介绍:

    在Android 10.0中,Google新增加了个功能。
    如果用户对新升级的APP不满意,可以通过“回到过去”,回滚到旧版。
    当然,如果新安装的apk出现了各种问题无法使用,也可以进行回滚的操作。
    这样的确可以极大的提升用户的体验,但是因为这块的逻辑较复杂,我们以module_crash_rollback_test为例,来看下具体的实现逻辑。


    代码路径如下:

    ./base/services/core/java/com/android/server/rollback
    ./base/core/java/android/content/rollback
    

    工作原理:

    如何验证这个功能是否逻辑生效,我们可以使用这个方法:

    1. adb install -r -d --enable-rollback --staged ***.apk
    2. adb reboot
    3. adb shell dumpsys rollback
    4. adb root
    5. adb shell am crash ***  (10 times)
    6. adb reboot
    7. adb wait-for-devices 1 mins
    8. adb shell dumpsys rollback
    

    我们即可从RollBack的状态,检查rollback机制是否被激活以及使用。
    dumpsys的code在代码中对应如下:

    代码路径为:frameworks/base/services/core/java/com/android/server/rollback/Rollback.java
        void dump(IndentingPrintWriter ipw) {
            synchronized (mLock) {
                ipw.println(info.getRollbackId() + ":");
                ipw.increaseIndent();
                ipw.println("-state: " + getStateAsString());
                ipw.println("-timestamp: " + getTimestamp());
                if (getStagedSessionId() != -1) {
                    ipw.println("-stagedSessionId: " + getStagedSessionId());
                }
                ipw.println("-packages:");
                ipw.increaseIndent();
                for (PackageRollbackInfo pkg : info.getPackages()) {
                    ipw.println(pkg.getPackageName()
                            + " " + pkg.getVersionRolledBackFrom().getLongVersionCode()
                            + " -> " + pkg.getVersionRolledBackTo().getLongVersionCode());
                }
                ipw.decreaseIndent();
                if (isCommitted()) {
                    ipw.println("-causePackages:");
                    ipw.increaseIndent();
                    for (VersionedPackage cPkg : info.getCausePackages()) {
                        ipw.println(cPkg.getPackageName() + " " + cPkg.getLongVersionCode());
                    }
                    ipw.decreaseIndent();
                    ipw.println("-committedSessionId: " + info.getCommittedSessionId());
                }
                if (mExtensionVersions.size() > 0) {
                    ipw.println("-extensionVersions:");
                    ipw.increaseIndent();
                    ipw.println(mExtensionVersions.toString());
                    ipw.decreaseIndent();
                }
                ipw.decreaseIndent();
            }
        }
    

    从dumpsys中,我们就可以看到rollback的当前执行状态。

        String getStateAsString() {
            synchronized (mLock) {
                return rollbackStateToString(mState);
            }
        }
    

    逻辑很简单,即为将RollBack中的mState变量值置为String并且打出。
    变量定义如下:

        /**
         * The current state of the rollback.
         * ENABLING, AVAILABLE, or COMMITTED.
         */
        @GuardedBy("mLock")
        private @RollbackState int mState;
    

    会有四个状态值,来对应当前的mState.

        @IntDef(prefix = { "ROLLBACK_STATE_" }, value = {
                ROLLBACK_STATE_ENABLING,
                ROLLBACK_STATE_AVAILABLE,
                ROLLBACK_STATE_COMMITTED,
                ROLLBACK_STATE_DELETED
        })
    

    那么在执行module_crash_rollback_test的时候,我们的逻辑是怎么生效的呢?
    首先是在rollbackmanagerservice中:

    /**
     * Service that manages APK level rollbacks. Publishes
     * Context.ROLLBACK_SERVICE.
     *
     * @hide
     */
    public final class RollbackManagerService extends SystemService {
    
        private RollbackManagerServiceImpl mService;
    
        public RollbackManagerService(Context context) {
            super(context);
        }
    
        @Override
        public void onStart() {
            mService = new RollbackManagerServiceImpl(getContext());
            publishBinderService(Context.ROLLBACK_SERVICE, mService);
        }
    
        @Override
        public void onUnlockUser(int user) {
            mService.onUnlockUser(user);
        }
    
        @Override
        public void onBootPhase(int phase) {
            if (phase == SystemService.PHASE_BOOT_COMPLETED) {
                mService.onBootCompleted();
            }
        }
    

    可以看到的是,在PHASE_BOOT_COMPLETED时,将会调用onBootCompleted的函数。
    如果看过之前的文章的同学,可能也明白了这个函数是在系统启动完成后,针对全局发出的通知。

        @AnyThread
        void onBootCompleted() {
            DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
                    mExecutor, properties -> updateRollbackLifetimeDurationInMillis());
    
            getHandler().post(() -> {
                updateRollbackLifetimeDurationInMillis();
                runExpiration();
    
                // Check to see if any rollback-enabled staged sessions or staged
                // rollback sessions been applied.
                List<Rollback> enabling = new ArrayList<>();
                List<Rollback> restoreInProgress = new ArrayList<>();
                Set<String> apexPackageNames = new HashSet<>();
                synchronized (mLock) {
                    Iterator<Rollback> iter = mRollbacks.iterator();
                    while (iter.hasNext()) {
                        Rollback rollback = iter.next();
                        if (!rollback.isStaged()) {
                            // We only care about staged rollbacks here
                            continue;
                        }
    
                        PackageInstaller.SessionInfo session = mContext.getPackageManager()
                                .getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
                        if (session == null || session.isStagedSessionFailed()) {
                            iter.remove();
                            rollback.delete(mAppDataRollbackHelper);
                            continue;
                        }
    
                        if (session.isStagedSessionApplied()) {
                            if (rollback.isEnabling()) {
                                enabling.add(rollback);
                            } else if (rollback.isRestoreUserDataInProgress()) {
                                restoreInProgress.add(rollback);
                            }
                        }
                        apexPackageNames.addAll(rollback.getApexPackageNames());
                    }
                }
    
                for (Rollback rollback : enabling) {
                    makeRollbackAvailable(rollback);
                }
    
                for (Rollback rollback : restoreInProgress) {
                    rollback.setRestoreUserDataInProgress(false);
                }
    
                for (String apexPackageName : apexPackageNames) {
                    // We will not recieve notifications when an apex is updated,
                    // so check now in case any rollbacks ought to be expired. The
                    // onPackagedReplace function is safe to call if the package
                    // hasn't actually been updated.
                    onPackageReplaced(apexPackageName);
                }
    
                synchronized (mLock) {
                    mOrphanedApkSessionIds.clear();
                }
    
                mPackageHealthObserver.onBootCompletedAsync();
            });
        }
    

    这段主要说的是在系统启动过程中,我们将会对rollback的功能开启,各个session的状态,以及实际的packageName进行replaced,restore userdata的操作。这边分析一下onPackageReplaced函数:

        /**
         * Called when a package has been replaced with a different version.
         * Removes all backups for the package not matching the currently
         * installed package version.
         */
        @WorkerThread
        private void onPackageReplaced(String packageName) {
            // TODO: Could this end up incorrectly deleting a rollback for a
            // package that is about to be installed?
            long installedVersion = getInstalledPackageVersion(packageName);
    
            synchronized (mLock) {
                Iterator<Rollback> iter = mRollbacks.iterator();
                while (iter.hasNext()) {
                    Rollback rollback = iter.next();
                    // TODO: Should we remove rollbacks in the ENABLING state here?
                    if ((rollback.isEnabling() || rollback.isAvailable())
                            && rollback.includesPackageWithDifferentVersion(packageName,
                            installedVersion)) {
                        iter.remove();
                        rollback.delete(mAppDataRollbackHelper);
                    }
                }
            }
        }
    

    当包被其他版本替换时调用时,我们会通过installedVersion来保存APK的版本号,
    并且在下面将会删除与当前安装的包版本不匹配的包的所有备份。
    在操作完,将会执行onBootCompletedAsync函数,而这边是进行的通知。

        /** Verifies the rollback state after a reboot and schedules polling for sometime after reboot
         * to check for native crashes and mitigate them if needed.
         */
        public void onBootCompletedAsync() {
            mHandler.post(()->onBootCompleted());
        }
    

    那么这个onBootCompleted在做什么工作呢?

        private void onBootCompleted() {
            RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
            if (!rollbackManager.getAvailableRollbacks().isEmpty()) {
                // TODO(gavincorkery): Call into Package Watchdog from outside the observer
                PackageWatchdog.getInstance(mContext).scheduleCheckAndMitigateNativeCrashes();
            }
    
            SparseArray<String> rollbackIds = popLastStagedRollbackIds();
            for (int i = 0; i < rollbackIds.size(); i++) {
                WatchdogRollbackLogger.logRollbackStatusOnBoot(mContext,
                        rollbackIds.keyAt(i), rollbackIds.valueAt(i),
                        rollbackManager.getRecentlyCommittedRollbacks());
            }
        }
    

    这边的重头戏来了,scheduleCheckAndMitigateNativeCrashes看上去和我们要验证的module_crash_rollback_test非常的相似。

        /**
         * Since this method can eventually trigger a rollback, it should be called
         * only once boot has completed {@code onBootCompleted} and not earlier, because the install
         * session must be entirely completed before we try to rollback.
         */
        public void scheduleCheckAndMitigateNativeCrashes() {
            Slog.i(TAG, "Scheduling " + mNumberOfNativeCrashPollsRemaining + " polls to check "
                    + "and mitigate native crashes");
            mShortTaskHandler.post(()->checkAndMitigateNativeCrashes());
        }
    

    只是打印了log,就来执行check的操作。

        /**
         * This method should be only called on mShortTaskHandler, since it modifies
         * {@link #mNumberOfNativeCrashPollsRemaining}.
         */
        private void checkAndMitigateNativeCrashes() {
            mNumberOfNativeCrashPollsRemaining--;
            // Check if native watchdog reported a crash
            if ("1".equals(SystemProperties.get("sys.init.updatable_crashing"))) {
                // We rollback everything available when crash is unattributable
                onPackageFailure(Collections.EMPTY_LIST, FAILURE_REASON_NATIVE_CRASH);
                // we stop polling after an attempt to execute rollback, regardless of whether the
                // attempt succeeds or not
            } else {
                if (mNumberOfNativeCrashPollsRemaining > 0) {
                    mShortTaskHandler.postDelayed(() -> checkAndMitigateNativeCrashes(),
                            NATIVE_CRASH_POLLING_INTERVAL_MILLIS);
                }
            }
        }
    

    这边就非常奇怪了,为什么会有sys.init.updatable_crashing这个systemproperties呢?
    这个properties是定义在什么地方?
    代码路径: system/core/init/service.cpp

        // If we crash > 4 times in 4 minutes or before boot_completed,
        // reboot into bootloader or set crashing property
        boot_clock::time_point now = boot_clock::now();
        if (((flags_ & SVC_CRITICAL) || is_process_updatable) && !(flags_ & SVC_RESTART)) {
            bool boot_completed = android::base::GetBoolProperty("sys.boot_completed", false);
            if (now < time_crashed_ + 4min || !boot_completed) {
                if (++crash_count_ > 4) {
                    if (flags_ & SVC_CRITICAL) {
                        // Aborts into bootloader
                        LOG(FATAL) << "critical process '" << name_ << "' exited 4 times "
                                   << (boot_completed ? "in 4 minutes" : "before boot completed");
                    } else {
                        LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times "
                                   << (boot_completed ? "in 4 minutes" : "before boot completed");
                        // Notifies update_verifier and apexd
                        SetProperty("sys.init.updatable_crashing_process_name", name_);
                        SetProperty("sys.init.updatable_crashing", "1");
                    }
                }
            } else {
                time_crashed_ = now;
                crash_count_ = 1;
            }
        }
    

    这里其实是对Crash的一个检查,如果在开机以后,规定时间内有四次以上的crash,然后就会触发这个properties的定义。
    同时会记录当前进程的名字:sys.init.updatable_crashing_process_name。
    但是在正常的过程中,这个应该不会出现。
    但是在我们之前测试步骤中,当我们连续crash apk多次,那么重启后是否就会激活rollback呢?
    应该是的,我们继续看看状态的改变过程。

        /**
         * Called when a process fails due to a crash, ANR or explicit health check.
         *
         * <p>For each package contained in the process, one registered observer with the least user
         * impact will be notified for mitigation.
         *
         * <p>This method could be called frequently if there is a severe problem on the device.
         */
        public void onPackageFailure(List<VersionedPackage> packages,
                @FailureReasons int failureReason) {
            if (packages == null) {
                Slog.w(TAG, "Could not resolve a list of failing packages");
                return;
            }
            mLongTaskHandler.post(() -> {
                synchronized (mLock) {
                    if (mAllObservers.isEmpty()) {
                        return;
                    }
                    boolean requiresImmediateAction = (failureReason == FAILURE_REASON_NATIVE_CRASH
                            || failureReason == FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
                    if (requiresImmediateAction) {
                        handleFailureImmediately(packages, failureReason);
                    } else {
                        for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
                            VersionedPackage versionedPackage = packages.get(pIndex);
                            // Observer that will receive failure for versionedPackage
                            PackageHealthObserver currentObserverToNotify = null;
                            int currentObserverImpact = Integer.MAX_VALUE;
    
                            // Find observer with least user impact
                            for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
                                ObserverInternal observer = mAllObservers.valueAt(oIndex);
                                PackageHealthObserver registeredObserver = observer.registeredObserver;
                                if (registeredObserver != null
                                        && observer.onPackageFailureLocked(
                                        versionedPackage.getPackageName())) {
                                    int impact = registeredObserver.onHealthCheckFailed(
                                            versionedPackage, failureReason);
                                    if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
                                            && impact < currentObserverImpact) {
                                        currentObserverToNotify = registeredObserver;
                                        currentObserverImpact = impact;
                                    }
                                }
                            }
    
                            // Execute action with least user impact
                            if (currentObserverToNotify != null) {
                                currentObserverToNotify.execute(versionedPackage, failureReason);
                            }
                        }
                    }
                }
            });
        }
    

    当package failureReason 的原因为Native_Crash和FAILURE_REASON_EXPLICIT_HEALTH_CHECK时,将会立刻对问题进行处理。
    使用函数为:handleFailureImmediately。

        /**
         * For native crashes or explicit health check failures, call directly into each observer to
         * mitigate the error without going through failure threshold logic.
         */
        private void handleFailureImmediately(List<VersionedPackage> packages,
                @FailureReasons int failureReason) {
            VersionedPackage failingPackage = packages.size() > 0 ? packages.get(0) : null;
            PackageHealthObserver currentObserverToNotify = null;
            int currentObserverImpact = Integer.MAX_VALUE;
            for (ObserverInternal observer: mAllObservers.values()) {
                PackageHealthObserver registeredObserver = observer.registeredObserver;
                if (registeredObserver != null) {
                    int impact = registeredObserver.onHealthCheckFailed(
                            failingPackage, failureReason);
                    if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
                            && impact < currentObserverImpact) {
                        currentObserverToNotify = registeredObserver;
                        currentObserverImpact = impact;
                    }
                }
            }
            if (currentObserverToNotify != null) {
                currentObserverToNotify.execute(failingPackage,  failureReason);
            }
        }
    

    在使用后,会执行execute的函数:

        @Override
        public boolean execute(@Nullable VersionedPackage failedPackage,
                @FailureReasons int rollbackReason) {
            if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
                rollbackAll();
                return true;
            }
    
            RollbackInfo rollback = getAvailableRollback(failedPackage);
            if (rollback == null) {
                Slog.w(TAG, "Expected rollback but no valid rollback found for " + failedPackage);
                return false;
            }
            rollbackPackage(rollback, failedPackage, rollbackReason);
            // Assume rollback executed successfully
            return true;
        }
    

    这里面我们主要关注的是NATIVE_CRASH的实现,所以将会去看rollbackAll的具体实现。

        private void rollbackAll() {
            Slog.i(TAG, "Rolling back all available rollbacks");
            RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
            List<RollbackInfo> rollbacks = rollbackManager.getAvailableRollbacks();
    
            // Add all rollback ids to mPendingStagedRollbackIds, so that we do not reboot before all
            // pending staged rollbacks are handled.
            synchronized (mPendingStagedRollbackIds) {
                for (RollbackInfo rollback : rollbacks) {
                    if (rollback.isStaged()) {
                        mPendingStagedRollbackIds.add(rollback.getRollbackId());
                    }
                }
            }
    
            for (RollbackInfo rollback : rollbacks) {
                VersionedPackage sample = rollback.getPackages().get(0).getVersionRolledBackFrom();
                rollbackPackage(rollback, sample, PackageWatchdog.FAILURE_REASON_NATIVE_CRASH);
            }
        }
    

    RollBackPackage具体的实现逻辑如下:

        /**
         * Rolls back the session that owns {@code failedPackage}
         *
         * @param rollback {@code rollbackInfo} of the {@code failedPackage}
         * @param failedPackage the package that needs to be rolled back
         */
        private void rollbackPackage(RollbackInfo rollback, VersionedPackage failedPackage,
                @FailureReasons int rollbackReason) {
            final RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
            int reasonToLog = WatchdogRollbackLogger.mapFailureReasonToMetric(rollbackReason);
            final String failedPackageToLog;
            if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) {
                failedPackageToLog = SystemProperties.get(
                        "sys.init.updatable_crashing_process_name", "");
            } else {
                failedPackageToLog = failedPackage.getPackageName();
            }
            VersionedPackage logPackageTemp = null;
            if (isModule(failedPackage.getPackageName())) {
                logPackageTemp = WatchdogRollbackLogger.getLogPackage(mContext, failedPackage);
            }
    
            final VersionedPackage logPackage = logPackageTemp;
            WatchdogRollbackLogger.logEvent(logPackage,
                    FrameworkStatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE,
                    reasonToLog, failedPackageToLog);
            final LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
                int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
                        RollbackManager.STATUS_FAILURE);
                if (status == RollbackManager.STATUS_SUCCESS) {
                    if (rollback.isStaged()) {
                        int rollbackId = rollback.getRollbackId();
                        synchronized (mPendingStagedRollbackIds) {
                            mPendingStagedRollbackIds.add(rollbackId);
                        }
                        BroadcastReceiver listener =
                                listenForStagedSessionReady(rollbackManager, rollbackId,
                                        logPackage);
                        handleStagedSessionChange(rollbackManager, rollbackId, listener,
                                logPackage);
                    } else {
                        WatchdogRollbackLogger.logEvent(logPackage,
                                FrameworkStatsLog
                                        .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
                                reasonToLog, failedPackageToLog);
                    }
                } else {
                    if (rollback.isStaged()) {
                        markStagedSessionHandled(rollback.getRollbackId());
                    }
                    WatchdogRollbackLogger.logEvent(logPackage,
                            FrameworkStatsLog
                                    .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
                            reasonToLog, failedPackageToLog);
                }
            });
    
            mHandler.post(() ->
                    rollbackManager.commitRollback(rollback.getRollbackId(),
                            Collections.singletonList(failedPackage),
                            rollbackReceiver.getIntentSender()));
        }
    

    这里面我们不去具体的分析某个session,而是回到前文中,提到的具体的状态,这里就会看到最后的这么一个逻辑。

            mHandler.post(() ->
                    rollbackManager.commitRollback(rollback.getRollbackId(),
                            Collections.singletonList(failedPackage),
                            rollbackReceiver.getIntentSender()));
    

    这里面是调用了rollbackManager的commitRollback方法:

        @Override
        public void commitRollback(int rollbackId, ParceledListSlice causePackages,
                String callerPackageName, IntentSender statusReceiver) {
            enforceManageRollbacks("commitRollback");
    
            final int callingUid = Binder.getCallingUid();
            AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
            appOps.checkPackage(callingUid, callerPackageName);
    
            getHandler().post(() ->
                    commitRollbackInternal(rollbackId, causePackages.getList(),
                        callerPackageName, statusReceiver));
        }
    

    其实也就是获取package,然后去通过commitRollbackInternal处理。

        /**
         * Performs the actual work to commit a rollback.
         * The work is done on the current thread. This may be a long running
         * operation.
         */
        @WorkerThread
        private void commitRollbackInternal(int rollbackId, List<VersionedPackage> causePackages,
                String callerPackageName, IntentSender statusReceiver) {
            Slog.i(TAG, "commitRollback id=" + rollbackId + " caller=" + callerPackageName);
    
            Rollback rollback = getRollbackForId(rollbackId);
            if (rollback == null) {
                sendFailure(
                        mContext, statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
                        "Rollback unavailable");
                return;
            }
            rollback.commit(mContext, causePackages, callerPackageName, statusReceiver);
        }
    

    rollback的commit将会去具体的更改某个rollback的状态:

        /**
         * Commits the rollback.
         */
        void commit(final Context context, List<VersionedPackage> causePackages,
                String callerPackageName, IntentSender statusReceiver) {
            synchronized (mLock) {
                if (!isAvailable()) {
                    sendFailure(context, statusReceiver,
                            RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
                            "Rollback unavailable");
                    return;
                }
    
                if (containsApex() && wasCreatedAtLowerExtensionVersion()) {
                    PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
                    if (extensionVersionReductionWouldViolateConstraint(mExtensionVersions, pmi)) {
                        sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
                                "Rollback may violate a minExtensionVersion constraint");
                        return;
                    }
                }
    
                // Get a context to use to install the downgraded version of the package.
                Context pkgContext;
                try {
                    pkgContext = context.createPackageContextAsUser(callerPackageName, 0,
                            UserHandle.of(mUserId));
                } catch (PackageManager.NameNotFoundException e) {
                    sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
                            "Invalid callerPackageName");
                    return;
                }
    
                PackageManager pm = pkgContext.getPackageManager();
                try {
                    PackageInstaller packageInstaller = pm.getPackageInstaller();
                    PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
                            PackageInstaller.SessionParams.MODE_FULL_INSTALL);
                    parentParams.setRequestDowngrade(true);
                    parentParams.setMultiPackage();
                    if (isStaged()) {
                        parentParams.setStaged();
                    }
                    parentParams.setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK);
    
                    int parentSessionId = packageInstaller.createSession(parentParams);
                    PackageInstaller.Session parentSession = packageInstaller.openSession(
                            parentSessionId);
    
                    for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
                        if (pkgRollbackInfo.isApkInApex()) {
                            // No need to issue a downgrade install request for apk-in-apex. It will
                            // be rolled back when its parent apex is downgraded.
                            continue;
                        }
                        PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
                                PackageInstaller.SessionParams.MODE_FULL_INSTALL);
                        String installerPackageName = mInstallerPackageName;
                        if (TextUtils.isEmpty(mInstallerPackageName)) {
                            installerPackageName = pm.getInstallerPackageName(
                                    pkgRollbackInfo.getPackageName());
                        }
                        if (installerPackageName != null) {
                            params.setInstallerPackageName(installerPackageName);
                        }
                        params.setRequestDowngrade(true);
                        params.setRequiredInstalledVersionCode(
                                pkgRollbackInfo.getVersionRolledBackFrom().getLongVersionCode());
                        if (isStaged()) {
                            params.setStaged();
                        }
                        if (pkgRollbackInfo.isApex()) {
                            params.setInstallAsApex();
                        }
                        int sessionId = packageInstaller.createSession(params);
                        PackageInstaller.Session session = packageInstaller.openSession(sessionId);
                        File[] packageCodePaths = RollbackStore.getPackageCodePaths(
                                this, pkgRollbackInfo.getPackageName());
                        if (packageCodePaths == null) {
                            sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
                                    "Backup copy of package: "
                                            + pkgRollbackInfo.getPackageName() + " is inaccessible");
                            return;
                        }
    
                        for (File packageCodePath : packageCodePaths) {
                            try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(packageCodePath,
                                    ParcelFileDescriptor.MODE_READ_ONLY)) {
                                final long token = Binder.clearCallingIdentity();
                                try {
                                    session.write(packageCodePath.getName(), 0,
                                            packageCodePath.length(),
                                            fd);
                                } finally {
                                    Binder.restoreCallingIdentity(token);
                                }
                            }
                        }
                        parentSession.addChildSessionId(sessionId);
                    }
    
                    final LocalIntentReceiver receiver = new LocalIntentReceiver(
                            (Intent result) -> {
                                int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                                        PackageInstaller.STATUS_FAILURE);
                                if (status != PackageInstaller.STATUS_SUCCESS) {
                                    // Committing the rollback failed, but we still have all the info we
                                    // need to try rolling back again, so restore the rollback state to
                                    // how it was before we tried committing.
                                    // TODO: Should we just kill this rollback if commit failed?
                                    // Why would we expect commit not to fail again?
                                    // TODO: Could this cause a rollback to be resurrected
                                    // if it should otherwise have expired by now?
                                    synchronized (mLock) {
                                        mState = ROLLBACK_STATE_AVAILABLE;
                                        mRestoreUserDataInProgress = false;
                                        info.setCommittedSessionId(-1);
                                    }
                                    sendFailure(context, statusReceiver,
                                            RollbackManager.STATUS_FAILURE_INSTALL,
                                            "Rollback downgrade install failed: "
                                                    + result.getStringExtra(
                                                    PackageInstaller.EXTRA_STATUS_MESSAGE));
                                    return;
                                }
    
                                synchronized (mLock) {
                                    if (!isStaged()) {
                                        // All calls to restoreUserData should have
                                        // completed by now for a non-staged install.
                                        mRestoreUserDataInProgress = false;
                                    }
    
                                    info.getCausePackages().addAll(causePackages);
                                    RollbackStore.deletePackageCodePaths(this);
                                    RollbackStore.saveRollback(this);
                                }
    
                                // Send success.
                                try {
                                    final Intent fillIn = new Intent();
                                    fillIn.putExtra(
                                            RollbackManager.EXTRA_STATUS,
                                            RollbackManager.STATUS_SUCCESS);
                                    statusReceiver.sendIntent(context, 0, fillIn, null, null);
                                } catch (IntentSender.SendIntentException e) {
                                    // Nowhere to send the result back to, so don't bother.
                                }
    
                                Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
    
                                for (UserInfo userInfo : UserManager.get(context).getUsers(true)) {
                                    context.sendBroadcastAsUser(broadcast,
                                            userInfo.getUserHandle(),
                                            Manifest.permission.MANAGE_ROLLBACKS);
                                }
                            }
                    );
    
                    mState = ROLLBACK_STATE_COMMITTED;
                    info.setCommittedSessionId(parentSessionId);
                    mRestoreUserDataInProgress = true;
                    parentSession.commit(receiver.getIntentSender());
                } catch (IOException e) {
                    Slog.e(TAG, "Rollback failed", e);
                    sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
                            "IOException: " + e.toString());
                }
            }
        }
    

    在执行完后,会将mState置为ROLLBACK_STATE_COMMITTED;

    mState = ROLLBACK_STATE_COMMITTED;
    

    所以,当我们检查初始化状态为

    ROLLBACK_STATE_ENABLING,

    开机后的状态为

    ROLLBACK_STATE_AVAILABLE,

    执行完crash,rollback后的状态为

    ROLLBACK_STATE_COMMITTED

    这个功能的实现和验证就成功了,实现应用回滚的具体操作。

    展开全文
  • 第六十七章 SQL命令 ROLLBACK

    千次阅读 2021-11-06 08:07:03
    文章目录 第六十七章 SQL命令 ROLLBACK大纲参数描述不回滚回滚日志事务挂起ObjectScript事务命令 第六十七章 SQL命令 ROLLBACK 回滚事务。 大纲 ROLLBACK [WORK] ROLLBACK TO SAVEPOINT pointname 参数 point...

    文章目录

    第六十七章 SQL命令 ROLLBACK

    回滚事务。

    大纲

    ROLLBACK [WORK]
    
    ROLLBACK TO SAVEPOINT pointname
    

    参数

    • pointname - 作为标识符指定的现有保存点的名称。

    描述

    ROLLBACK语句将回滚事务,撤消已执行但未提交的工作,减少$TLEVEL事务级别计数器,并释放锁。
    ROLLBACK用于将数据库恢复到以前的一致状态。

    • ROLLBACK回滚当前事务期间完成的所有工作,将$TLEVEL事务级别计数器重置为0,并释放所有锁。
      这会将数据库恢复到事务开始之前的状态。
      ROLLBACKROLLBACK WORK是等价的语句;
      这两个版本都支持兼容性。
    • ROLLBACK TO SAVEPOINT pointname将回滚自指定保存点以来已完成的所有工作,并按未完成的保存点的数量递减$TLEVEL事务级别计数器。
      当所有保存点都被回滚或提交,并且事务级别计数器重置为零时,事务就完成了。
      如果指定的保存点不存在,或者已经回滚,ROLLBACK将发出SQLCODE -375错误并回滚整个当前事务。

    回滚到SAVEPOINT必须指定一个点名。
    如果不这样做,将导致SQLCODE -301错误。

    如果事务操作未能成功完成,则会发出SQLCODE -400错误。

    不回滚

    ROLLBACK操作不影响以下项目:

    • 回滚不会减少默认类的IDKey计数器。
      IDKey是由$INCREMENT(或$SEQUENCE)自动生成的,它维护一个独立于SQL事务的计数。
    • 回滚不会逆转缓存查询的创建、修改或清除。
      这些操作不被视为事务的一部分。
    • 在事务中发生的DDL操作或调优表操作可以创建并运行临时例程。
      这个临时例程与缓存查询一样被处理。
      也就是说,临时例程的创建、编译和删除不被视为事务的一部分。
      临时例程的执行被认为是事务的一部分。

    回滚日志

    提示回滚发生的消息和回滚操作中遇到的错误都记录在MGR目录下的Messages.log文件中。
    您可以通过“管理门户系统操作”、“系统日志”、“消息日志”选项查看“Messages.Log”。

    事务挂起

    %SYSTEM.Process类的TransactionsSuspending()方法可用于挂起和恢复系统范围内的所有当前事务。挂起事务会挂起更改的日志记录。因此,如果在当前事务期间发生事务挂起,则ROLLBACK不能回滚在事务挂起期间所做的任何更改;但是,回滚将回滚在事务挂起生效之前或之后在当前事务期间所做的任何更改。

    ObjectScript事务命令

    ObjectScriptSQL TRANSACTION命令完全兼容且可互换,但以下情况除外:

    如果没有当前事务,ObjectScript TSTARTSQL START TRANSACTION都会启动事务。但是,START TRANSACTION不支持嵌套事务。因此,如果需要(或可能需要)嵌套事务,最好使用TSTART启动事务。如果需要与SQL标准兼容,请使用START TRANSACTION

    ObjectScript事务处理为嵌套事务提供有限的支持。SQL事务处理为事务内的保存点提供支持。

    ClassMethod ROLLBACK()
    {
    	&sql(SET TRANSACTION %COMMITMODE EXPLICIT)
    	w !,"Set transaction mode, SQLCODE=",SQLCODE
    	w !,"Transaction level=",$TLEVEL
    	&sql(START TRANSACTION)
    	w !,"Start transaction, SQLCODE=",SQLCODE
    	w !,"Transaction level=",$TLEVEL
    	&sql(SAVEPOINT a)
    	w !,"Set Savepoint a, SQLCODE=",SQLCODE
    	w !,"Transaction level=",$TLEVEL
    	&sql(SAVEPOINT b)
    	w !,"Set Savepoint b, SQLCODE=",SQLCODE
    	w !,"Transaction level=",$TLEVEL
    	&sql(SAVEPOINT c)
    	w !,"Set Savepoint c, SQLCODE=",SQLCODE
    	w !,"Transaction level=",$TLEVEL
    	&sql(ROLLBACK)
    	w !,"Rollback transaction, SQLCODE=",SQLCODE
    	w !,"Transaction level=",$TLEVEL
    }
    
    DHC-APP>d ##class(PHA.TEST.SQLCommand).ROLLBACK()
     
    Set transaction mode, SQLCODE=0
    Transaction level=0
    Start transaction, SQLCODE=0
    Transaction level=1
    Set Savepoint a, SQLCODE=0
    Transaction level=2
    Set Savepoint b, SQLCODE=0
    Transaction level=3
    Set Savepoint c, SQLCODE=0
    Transaction level=4
    Rollback transaction, SQLCODE=0
    Transaction level=0
    

    以下嵌入式SQL示例演示了回滚到保存点名称如何将事务级别($TLEVEL)恢复到紧靠指定保存点之前的级别:

    ClassMethod ROLLBACK1()
    {
    	&sql(SET TRANSACTION %COMMITMODE EXPLICIT)
    	w !,"Set transaction mode, SQLCODE=",SQLCODE
    	w !,"Transaction level=",$TLEVEL
    	&sql(START TRANSACTION)
    	w !,"Start transaction, SQLCODE=",SQLCODE
    	w !,"Transaction level=",$TLEVEL
    	&sql(SAVEPOINT a)
    	w !,"Set Savepoint a, SQLCODE=",SQLCODE
    	w !,"Transaction level at a=",$TLEVEL
    	&sql(SAVEPOINT b)
    	w !,"Set Savepoint b, SQLCODE=",SQLCODE
    	w !,"Transaction level at b=",$TLEVEL
    	&sql(ROLLBACK TO SAVEPOINT b)
    	w !,"Rollback to b, SQLCODE=",SQLCODE
    	w !,"Rollback transaction level=",$TLEVEL
    	&sql(SAVEPOINT c)
    	w !,"Set Savepoint c, SQLCODE=",SQLCODE
    	w !,"Transaction level at c=",$TLEVEL
    	&sql(SAVEPOINT d)
    	w !,"Set Savepoint d, SQLCODE=",SQLCODE
    	w !,"Transaction level at d=",$TLEVEL
    	&sql(COMMIT)
    	w !,"Commit transaction, SQLCODE=",SQLCODE
    	w !,"Transaction level=",$TLEVEL
    }
    
    DHC-APP>d ##class(PHA.TEST.SQLCommand).ROLLBACK1()
     
    Set transaction mode, SQLCODE=0
    Transaction level=0
    Start transaction, SQLCODE=0
    Transaction level=1
    Set Savepoint a, SQLCODE=0
    Transaction level at a=2
    Set Savepoint b, SQLCODE=0
    Transaction level at b=3
    Rollback to b, SQLCODE=0
    Rollback transaction level=2
    Set Savepoint c, SQLCODE=0
    Transaction level at c=3
    Set Savepoint d, SQLCODE=0
    Transaction level at d=4
    Commit transaction, SQLCODE=0
    Transaction level=0
    
    展开全文
  • Win系统多点还原软件(RRx)RollBack Rx Pro V10.7带序列号版,可以对系统进行快照,多点记录,随时还原到记录点,快速还原
  • RollBack 10.2 雨过天晴 20161207 请分别看压缩包注释,不用winRAR打开可能看不到哦。
  • PDO::rollBack讲解

    2020-12-19 23:50:28
    PDO::rollBack PDO::rollBack — 回滚一个事务(PHP 5 >= 5.1.0, PECL pdo >= 0.1.0) 说明 语法 bool PDO::rollBack ( void ) 回滚由PDO::beginTransaction()发起的当前事务。如果没有事务激活,将抛出一个 ...
  • 如果在commit之前发生异常,进入catch里显式rollback,会造成什么隐形后果,如果在catch里去掉rollback,因为也没有commit所以数据还是不会提交,什么情况下会rollback才会真正发挥作用,并且这个作...
  • Win系统多点还原软件(RRx)RollBack Rx Pro V10.7无限制序列号版
  • CREATE TABLE postgres=# \dt List of relations Schema | Name | Type | Owner --------+------+-------+---------- public | test | table | postgres (1 row) postgres=# rollback ; ROLLBACK postgres=# \dt No...
  • 9.2.4 执行ROLLBACK命令

    2021-05-08 01:24:47
    9.2.4 执行ROLLBACK命令需要记住的是,如果出现任何错误,那么后台进程就会完全自动地回滚正在进行的事务。例如,如果启动某个事务的会话失败(运行用户进程的计算机可能重启,或者网络连接可能中断),那么PMON进程会...
  • 使用ROLLBACK既然我们已经知道了什么是事务处理,下面讨论事务处理的管理中所涉及的问题。管理事务处理的关键在于将SQL语句组分解为逻辑块,并明确规定数据何时应该回退,何时不应该回退。MySQL使用下面的语句来标识...
  • MYSQL的COMMIT和ROLLBACK使用讲解

    千次阅读 2021-02-07 12:06:02
    MYSQL的COMMIT和ROLLBACK从功能上划分,SQL 语言可以分为DDL,DML和DCL三大类。1. DDL(Data Definition Language)数据定义语言,用于定义和管理 SQL数据库中的所有对象的语言 ;CREATE---创建表ALTER---修改表DROP---...
  • The rollback SQL statement is used to manually rollback transactions in MS SQL Server. 回滚SQL语句用于在MS SQL Server中手动回滚事务。 Transactions in SQL Server are used to execute a set of SQL...
  • (4)正常提交如exit等commit,非正常提交如突然断电rollback 四,ROLLBACK:回滚语句使数据库状态回到上次最后提交事务的状态 ROLLBACK [WORK] TO [SAVEPOINT]//回退到某一点 一个事务起始于DML语句,终止于DDL、DCL...
  • oracle中rollback的使用

    2021-05-01 11:45:06
    ----》rollback使用SQL> create table tbl(name varchar2(10));Table created.SQL> insert into tbl values('zhiqiao');1 row created.SQL> select * from tbl;NAME----------zhiqiaoSQL> delete tbl;1 ...
  • MySql之commit、rollback等事务控制命令

    千次阅读 2021-03-03 18:02:39
    MYSQL 事务处理主要有两种方法1、用 begin, rollback, commit来实现begin或/start transaction)开始一个事务rollback事务回滚commit事务确认2、直接用 SET 来改变 MySQL 的自动提交模式:set autocommit=0禁止自动...
  • jdbc rollback Connection conn = null; Statement smt = null; ResultSet result = null; // 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/...
  • MySQL的rollback--大事务回滚

    千次阅读 2021-12-06 14:53:46
    +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | innodb_rollback_on_timeout | OFF | | innodb_rollback_segments | 128 | +----------------------...
  • 导读有时候会发生事务超时的情况,此时MySQL会返回类似这样的错误:那事务...innodb_rollback_on_timeout变量这是官方文档5.7的对innodb_rollback_on_timeout的解释:Command-Line Format--innodb_rollback_on_timeout...
  • @Transactional(rollbackFor)

    2021-10-27 15:03:52
    在回滚的设置上,spring提供的是rollbackFor,jdk提供的是rollbackOn,在使用方法上是一致的。 这两个注解在我有限的测试里表现是一样的。 用在哪里 @Transactional注解既可以写在方法上也可以写在类上。写在类上则...
  • Caused by: java.lang.IllegalStateException: Failed to rollback to checkpoint/savepoint hdfs://127.0.0.1/flink-checkpoints/78f7cb6b577fe6db19648ca63607e640/chk-6976. Cannot map checkpoint/savepoint ...
  • Evaluation of rollback points on multiprocessor systems Evaluation of Rollback Points on Multiprocessor Systems Kiyomitsu Yoneda, Takashi Matsubara, and Yoshiaki Koga Department of Computer ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 318,049
精华内容 127,219
关键字:

rollback

友情链接: translation .rar