كيف يمكنني إلغاء الاستعلام منذ فترة طويلة باستخدام الربيع وJDBCTemplate؟

StackOverflow https://stackoverflow.com/questions/1054642

  •  20-08-2019
  •  | 
  •  

سؤال

والطبقة java.sql.Statement JDBC لديها طريقة cancel(). يمكن أن يسمى هذا في موضوع آخر لإلغاء بيان قيد التشغيل حاليا.

وكيف يمكنني تحقيق ذلك باستخدام الربيع؟ لا أستطيع أن أجد وسيلة للحصول على إشارة إلى بيان عند تشغيل الاستعلام. ولا يمكنني أن أجد طريقة إلغاء مثل.

إليك بعض التعليمات البرمجية. تخيل هذا يستغرق فترة تصل إلى 10 ثانية لتنفيذ، وأحيانا على طلب المستخدم، أريد أن إلغاء ذلك:

    final int i = simpleJdbcTemplate.queryForInt("select max(gameid) from game");

وكيف لي أن تعديل هذا ما لدي إشارة إلى كائن java.sql.Statement؟

هل كانت مفيدة؟

المحلول

واسمحوا لي أن تبسيط الجواب oxbow_lakes ل: يمكنك استخدام البديل PreparedStatementCreator من أسلوب الاستعلام للوصول إلى البيان

وهكذا التعليمات البرمجية:

final int i = simpleJdbcTemplate.queryForInt("select max(gameid) from game");

ويجب أن تتحول إلى:

final PreparedStatement[] stmt = new PreparedStatement[1];
final int i = (Integer)getJdbcTemplate().query(new PreparedStatementCreator() {
    public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
        stmt[0] = connection.prepareStatement("select max(gameid) from game");
        return stmt[0];
    }
}, new ResultSetExtractor() {
    public Object extractData(ResultSet resultSet) throws SQLException, DataAccessException {
        return resultSet.getString(1);
    }
});

والآن لإلغاء يمكنك الاتصال فقط

stmt[0].cancel()

وربما كنت تريد أن تعطي إشارة إلى stmt لبعض الصفحات الأخرى قبل بالفعل تشغيل الاستعلام، أو لمجرد تخزينه كما متغير عضو. خلاف ذلك، لا يمكن إلغاء أي شيء حقا ...

نصائح أخرى

ويمكنك تنفيذ الأشياء عن طريق وسائل JdbcTemplate التي تسمح لك بالمرور في PreparedStatementCreator. هل يمكن دائما استخدام هذا لاعتراض الدعاء (ربما باستخدام Proxy) الذي تسبب في cancel أن يحدث على موضوع منفصل أصبح بعض cond true.

public Results respondToUseRequest(Request req) {
    final AtomicBoolean cond = new AtomicBoolean(false);
    requestRegister.put(req, cond);
    return jdbcTemplate.query(new PreparedStatementCreator() {
             public PreparedStatement createPreparedStatement(Connection conn) {
               PreparedStatement stmt = conn.prepareStatement();
               return proxyPreparedStatement(stmt, cond);
             }
         }, 
         new ResultSetExtractor() { ... });
}        
يمكن أن تكون هي نفسها إلغاء

وهذا canceller عند الانتهاء بنجاح. على سبيل المثال

private final static ScheduledExecutorService scheduler =
                 Executors.newSingleThreadedScheduledExecutor();  

PreparedStatement proxyPreparedStatement(final PreparedStatement s, AtomicBoolean cond) {
    //InvocationHandler delegates invocations to the underlying statement
    //but intercepts a query 
    InvocationHandler h = new InvocationHandler() {

        public Object invoke(Object proxy, Method m, Object[] args) {
            if (m.getName().equals("executeQuery") {
                Runnable cancel = new Runnable() {
                    public void run() { 
                        try {
                            synchronized (cond) {
                                while (!cond.get()) cond.wait();
                                s.cancel(); 
                            }
                        } catch (InterruptedException e) { }
                    } 
                }
                Future<?> f = scheduler.submit(cancel);
                try {
                    return m.invoke(s, args);
                } finally {
                    //cancel the canceller upon succesful completion
                    if (!f.isDone()) f.cancel(true); //will cause interrupt
                }
            }
            else {
                return m.invoke(s, args);
            }   
        }

    }

    return (PreparedStatement) Proxy.newProxyInstance(
                getClass().getClassLoader(), 
                new Class[]{PreparedStatement.class}, 
                h);

وحتى الآن التعليمات البرمجية التي يتم الاستجابة لإلغاء المستخدم ستبدو:

cond.set(true);
synchronized (cond) { cond.notifyAll(); }

وأفترض التي كتبها ربيع تقصد استخدام JdbcDaoTemplate و / أو JdbcTemplate؟ إذا كان الأمر كذلك، وهذا لا يساعد حقا أو تعيق لكم في حل مشكلتك.

وسوف أفترض حالة استخدامك هو أنك تنفيذ عملية DAO في موضوع واحد، وموضوع آخر يأتي في ويريد إلغاء العملية موضوع الأول.

والمشكلة الأولى لديك ليحل هو، كيف يمكن للموضوع الثاني يعرف أي واحد لإلغاء؟ هذا هو واجهة المستخدم الرسومية مع عدد محدد من المواضيع، أو ملقم مع عدة؟

وبمجرد حل هذا الجزء، تحتاج إلى معرفة كيفية إلغاء ما ورد في موضوع الأول. واحد من شأنه مقاربة بسيطة لهذا أن يكون لتخزين PreparedStatement الخيط الأول في حقل في مكان ما (ربما في حقل بسيط، وربما في خريطة موضوع ID للبيانات)، مما يتيح للموضوع الثاني لتأتي في، استرداد دعوة statwmentand إلغاء () عليه.

ونضع في اعتبارنا أنه من الممكن أن إلغاء () قد منع تماما، وهذا يتوقف على سائق JDBC وقاعدة البيانات. أيضا، تأكد من أن نفكر بجدية حول المزامنة هنا، والمواضيع الخاصة بك وسوف ندخل في معركة.

ويمكنك تسجيل الكائن رد من نوع StatementCallback على JdbcTemplate التي سوف تحصل على تنفيذها مع بيان النشط حاليا كمعلمة. في هذا الاستدعاء ثم يمكنك إلغاء البيان:

simpleJdbcTemplate.getJdbcOperations().execute(new StatementCallback() {

    @Override
    public Object doInStatement(final Statement statement) throws SQLException, DataAccessException {
        if (!statement.isClosed()) {
            statement.cancel();
        }

        return null;
    }
});
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top