首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java异步MySQL查询

问Java异步MySQL查询
EN

Stack Overflow用户
提问于 2015-12-06 12:00:13
回答 2查看 6.7K关注 0票数 1

首先,我对线程安全编程没有多少经验。

我有一个MySQL类,我希望在多个线程中使用一个实例来防止主线程中的阻塞代码。我读过关于连接池的文章,但我希望保持它的简单性。

这是我的MySQL课程:

代码语言:javascript
复制
package com.vanillage.bukkitutils.mysql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

public class MySQL {
    private final String host;
    private final int port;
    private final String database;
    private final String user;
    private final String password;
    private Connection connection;

    public MySQL(String host, int port, String database, String user, String password) {
        if (host == null) {
            //TODO
        }

        if (database == null) {
            //TODO
        }

        if (user == null) {
            //TODO
        }

        if (password == null) {
            //TODO
        }

        this.host = host;
        this.port = port;
        this.database = database;
        this.user = user;
        this.password = password;
    }

    public String getHost() {
        return host;
    }

    public int getPort() {
        return port;
    }

    public String getDatabase() {
        return database;
    }

    public String getUser() {
        return user;
    }

    public String getPassword() {
        return password;
    }

    public Connection getConnection() {
        return connection;
    }

    public synchronized void connect() throws SQLException {
        connection = DriverManager.getConnection("jdbc:mysql://" + host + ":" + port + "/" + database + "?autoReconnect=true", user, password);
    }

    public synchronized void checkConnection(int timeout) throws SQLException {
        if (connection == null) {
            connect();
        } else {
            boolean connectionValid = false;

            try {
                connectionValid = connection.isValid(timeout);
            } catch (SQLException e) {
                e.printStackTrace();
                connect();
                connectionValid = true;
            }

            if (!connectionValid) {
                connect();
            }
        }
    }

    public synchronized ResultSet query(String query) throws SQLException {
        return connection.prepareStatement(query).executeQuery();
    }

    public synchronized boolean update(String query) throws SQLException {
        return connection.prepareStatement(query).execute();
    }

    public synchronized void close() throws SQLException {
        if (connection != null) {
            connection.close();
            connection = null;
        }
    }

    public synchronized boolean hasConnection(boolean checkOpen, boolean checkValid, int timeout) throws SQLException {
        return connection != null && (!checkOpen || !connection.isClosed()) && (!checkValid || connection.isValid(timeout));
    }

    @Override
    public String toString() {
        return host + ":" + port + ", " + database + ", " + user + ", " + password;
    }
}

是否有可能使用同步关键字使我的MySQL类线程安全,因为我已经在上面的代码中使用了它?

我从不同的线程中这样使用这个类:

代码语言:javascript
复制
try {
    mySQL.checkConnection(0);

    try {
        ResultSet resultSet = mySQL.query("SELECT * FROM Example");

        if (resultSet.next()) {
            System.out.println(resultSet.getString("Example"));
        }
    } catch (SQLException e) {
        System.out.println("Error while executing query: " + e.getMessage());
    }
} catch (SQLException e) {
    System.out.println("Could not create a valid connection: " + e.getMessage());
}

我的问题是:线程安全吗?

编辑:

代码语言:javascript
复制
package testprogramm;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class TestProgramm {
    private static final Scanner scanner = new Scanner(System.in);
    private static Map<String, ComboPooledDataSource> dataSources = new HashMap<>();

    public static void main(String[] args) {
        //setup connections
        ComboPooledDataSource testDataSource = new ComboPooledDataSource();

        try {
            testDataSource.setDriverClass("com.mysql.jdbc.Driver");
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }

        testDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/database");
        testDataSource.setUser("user");
        testDataSource.setPassword("password");
        dataSources.put("test", testDataSource);

        while (true) {
            String line = scanner.nextLine();
            ComboPooledDataSource dataSource = dataSources.get(line);

            if (dataSource != null) {
                new Thread(new Runnable() {
                    ComboPooledDataSource dataSource = null;

                    public Runnable init(ComboPooledDataSource dataSource) {
                        this.dataSource = dataSource;
                        return this;
                    }

                    @Override
                    public void run() {
                        try {
                            Connection connection = dataSource.getConnection();
                            PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM Example");
                            ResultSet resultSet = preparedStatement.executeQuery();
                            int i = 0;

                            while (resultSet.next()) {
                                i ++;
                            }

                            resultSet.close();//TODO: move to finally clause with null check and try/catch
                            preparedStatement.close();
                            connection.close();
                            System.out.println(i + " entries");
                        } catch (SQLException e) {
                            System.out.println("Error while executing statement: " + e.getMessage());
                        }
                    }
                }.init(dataSource)).start();
            } else {
                System.out.println("No such connection");
            }
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-12-06 12:25:21

你的问题是:线程安全吗?

我的回答是:不,不是。

打破它的最简单的方法:让一个线程调用mySQL.getConnection().close();

除此之外:大多数连接根本不喜欢并行语句。它的交易范围应该是什么?

您应该认真地使用,,而不是考虑使用连接池。我最喜欢的选择是c3p0。有关快速启动示例,请参见http://www.mchange.com/projects/c3p0/#quickstart。

使其安全

不是传递MySQL的实例,而是创建和配置一个ComboPooledDataSource (或任何其他想要使用的DataSource )。然后在类中,从这个池中获取一个Connection,执行您的SQL语句,然后关闭它。实现这一目的的最方便的方法是使用Java 7引入的具有资源的尝试:

代码语言:javascript
复制
try(Connection con = pool.getConnection();
    PreparedStatement ps = con.prepareStatement("SELECT * FROM whatever");
    ResultSet rs = ps.executeQuery()) {

  while(rs.next()) {
    //handle resultset
  }
}

有关现有类的更多信息

如果你这么做的话,你就不能清理一大堆陈述。

代码语言:javascript
复制
public synchronized ResultSet query(String query) throws SQLException {
    //Statement never closed
    return connection.prepareStatement(query).executeQuery();
}

public synchronized boolean update(String query) throws SQLException {
    //Statement never closed
    return connection.prepareStatement(query).execute();
}
票数 2
EN

Stack Overflow用户

发布于 2018-09-06 06:40:17

另一种选择是使用异步驱动程序,比如J异步-sql。

它是这样使用的:

代码语言:javascript
复制
// Connect to DB
Connection connection = new MySQLConnection(
  new Configuration(
    "username",
    "host.com",
    3306,
    "password",
    "schema"
  )
);
CompletableFuture<?> connectFuture = connection.connect()
// Wait for connection to be ready   
// ...    
// Execute query
CompletableFuture<QueryResult> future =             
connection.sendPreparedStatement("select * from table");
// Close the connection
connection.disconnect().get()

希望这能有所帮助。

免责声明:我维护这个项目。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34117164

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档