简体   繁体   中英

PostgreSQL's XMIN in Oracle & MySQL

I'm trying to get the equivalent for this code on Oracle & MySQL

if(vardbtype.equals("POSTGRESQL")){
            Long previousTxId = 0L;
            Long nextTxId = 0L;

            Class.forName("org.postgresql.Driver");
            System.out.println("----------------------------");

            try(Connection c = DriverManager.getConnection("jdbc:postgresql://localhost:5432/"+ vardbserver, vardbuser, vardbpassword);
                 PreparedStatement stmts = c.prepareStatement("SELECT * FROM "+ vardbname +" where xmin::varchar::bigint > ? and xmin::varchar::bigint < ? ");
                 PreparedStatement max = c.prepareStatement("select max(xmin::varchar::bigint) as txid from "+ vardbname)
                ) {
                c.setAutoCommit(false);

                while(true) {
                    stmts.clearParameters();

                    try(ResultSet rss = max.executeQuery()) {
                        if(rss.next()) {
                            nextTxId = rss.getLong(1);
                        }
                    }
                    stmts.setLong(1, previousTxId);
                    stmts.setLong(2, nextTxId + 1);
                    try(ResultSet rss = stmts.executeQuery()) {
                        while(rss.next()) {
                            String message = rss.getString("MESSAGE");
                            System.out.println("Message = " + message);
                            TextMessage mssg = session.createTextMessage(message);
                            System.out.println("Sent: " + mssg.getText());
                            producer.send(mssg);
                        }
                        previousTxId = nextTxId;
                    }
                    Thread.sleep(batchperiod2);
                }
            }
        }

Basically, the code works to get contents inside a database's table and sent it to ActiveMQ. And when the table updated, it will sent the content that just updated (not sending the past that was sent). But this code only works on PostgreSQL

Then i'm planning to create an "if" function. So i can use another database to getting the data (Oracle and MySQL).

I guess i must change this code right?

 try(Connection c = DriverManager.getConnection("jdbc:postgresql://localhost:5432/"+ vardbserver, vardbuser, vardbpassword);
             PreparedStatement stmts = c.prepareStatement("SELECT * FROM "+ vardbname +" where xmin::varchar::bigint > ? and xmin::varchar::bigint < ? ");
             PreparedStatement max = c.prepareStatement("select max(xmin::varchar::bigint) as txid from "+ vardbname)
            ) {

A couple thoughts supplemental to Thorsten's answer.

First, xmin is a system column which is, iirc, stored in the row header on disk. It is updated by writes. I have not yet run into a case where the transaction id's don't increase. However, there has to be some wraparound point. I think you are better off with a trigger which stores the transaction ids in another table for processing for this reason (and using that to process things).

For Oracle and MySQL, underlying storage is sufficiently different that I don't see how you can do this directly.

If you want a common solution you want a queue table where you can use a trigger to insert waiting copies, and then select/delete from that in your worker. This will likely work better on MySQL than on PostgreSQL, and for Oracle you want to look for index-oriented tables. If autovacuum has trouble keeping up, ask more questions or hire a consultant.

After further research

InnoDB provides a DB_TRX_ID column which is similar. Note you cannot assume you have this column if you are running MySQL because MySQL has different table storage engines and not all even support transactions. So that is an important limitation.

I was unable to locate a similar column on Oracle.

This script is looking in intervals at a table and putting out all inserted messages since that last loop.

PostgreSQL stores the transaction number that inserted a record, so this can be used to find the newly inserted records (although I am not sure whether it is guaranteed for a new transaction to have a higher number than all previous ones as the script assumes).

Other DBMS don't have this pseudo column. So you would have to have a timestamp column in your table and use this instead. You'd have to change the two queries as well as the code to match the data type (I suppose java.sql.Timestamp instead of Long , but I am no Java guy).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM