如何在多个 类 上一次连接到 MySQL 数据库
How to connect to MySQL database once over multiple classes
我的程序包含许多 classes,其中一半使用 MySQL 数据库。现在,我为每个 class 单调乏味地连接到 MySQL。我知道这是一个坏习惯,我知道这是一团糟,这就是为什么我想知道是否有一种方法可以一次性连接 class。不过,我不确定如何将此连接传递给 classes。和使用参数类似,还是完全不同?
如果有人需要参考,这里是我的一些 classes:
import ~~~
public class LoginVerify {
public LoginVerify() {
String url = "jdbc:mysql://localhost:3306/grades";
String username = "root";
String password = "root";
JPasswordField jpf = new JPasswordField(10);
JLabel jl = new JLabel("Password: ");
jl.setFont(new Font("Times New Roman", Font.PLAIN, 15));
JTextField username1 = new JTextField(10);
JLabel label = new JLabel("Username: ");
label.setFont(new Font("Times New Roman", Font.PLAIN, 15));
final JButton okay = new JButton("Ok");
okay.setBackground(Color.WHITE);
okay.setFont(new Font("Times New Roman", Font.PLAIN, 15));
final JButton cancel = new JButton("Cancel");
cancel.setBackground(Color.WHITE);
cancel.setFont(new Font("Times New Roman", Font.PLAIN, 15));
Object[] message = {
label, username1,
jl, jpf,
};
int value = JOptionPane.showOptionDialog(
null,
message,
"LOGIN",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
new Object[]{okay, cancel},
okay);
if (value == 0) {
String user = username1.getText();
char[] p = jpf.getPassword();
String pswrd = String.valueOf(p);
System.out.println("user: " + user);
System.out.println("password: " + pswrd);
// CONNECTION STARTS HERE
try {
Connection connection = DriverManager.getConnection(url, username, password);
System.out.println("connection success!!");
String sql = "SELECT * FROM user_info WHERE user_id = ? && user_password = ?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, user);
statement.setString(2, pswrd);
ResultSet rs = statement.executeQuery();
while(rs.next()){
String name = rs.getString("user_name");
System.out.println(name);
new UserMain(user, name, password, null);
}
ResultSet rows = statement.executeQuery();
if (!rows.next() ) {
JLabel l = new JLabel("Username or password incorrect, please try again.");
l.setFont(new Font("Times New Roman", Font.PLAIN, 15));
l.setHorizontalAlignment(SwingConstants.CENTER);
JOptionPane.showMessageDialog(null, l, "ERROR", JOptionPane.PLAIN_MESSAGE);
new LoginVerify();
}
} catch (SQLException e) {
System.out.println("& i oop");
e.printStackTrace();
}
} else if (value == 1) {
JOptionPane.getRootFrame().dispose();
} else System.exit(0);
return;
}
}
你问的其实很复杂。作为一般规则,您 而不是 想要在不相关的代码位之间进行紧密绑定,因此从表面上看,'reuse the connection' 是一个可怕的想法。
不幸的是,数据库连接非常繁重,您也不想一秒钟创建大量的连接。
因此,解决方案是一个令人费解的混乱局面。按说,'convoluted mess'应该先让你走:真的吗?这个问题还没解决?但是,这是大多数情况下没有的情况之一。不过有很好的解决方法。
连接池
你要找的是一个叫做 DB 连接池库的东西。
这些库为您提供了一个 API 接入点,可以让您建立连接。完成后,您不会关闭它,而是将其交还(有时通过关闭它来完成 - 但随后您使用的库将为您提供代理连接,并且在代理上调用 close() 并不是真的关闭它,它只是将它标记为可供下一个调用者使用。
真正复杂的原因是你可以对连接做各种有状态的事情(例如,使用mysql的SET
命令,你可以改变一大堆奇怪的事情持续整个连接),并且连接通常会在一段时间后被数据库引擎破坏,所以仅仅给代码一个池中的连接是不够的 - 你需要 'test' 如果它仍然 'works'首先,运行 一大堆 SET 语句或以其他方式撤消先前使用该连接的代码造成的任何损坏。
那,而且,你想要一个限制器:如果已经有 10 个到同一个数据库的连接仍在进行中,那么对 'get a connection' 的调用应该只是阻塞并等待其中一个10 个已在进行中的连接将交回池中。
这 非常 太多的方面,作为新手一天就搞定了。
因此,获得一个漂亮的、预先编写的开源库来完成所有这些工作。或者,接受你每次都只是建立一个连接,让数据库引擎为它操心。您当然可以获取建立新连接的代码并将其粘贴在某个地方的静态方法中,然后调用它。现在你至少只有一个地方可以编辑 JDBC URL 等等。
那里的首选连接池是 HikariCP。
您的代码有缺陷
- 永远不要通过 'print stack trace and keep going' 处理异常。根据定义,您不知道发生了什么(显然是这样——您的 catch 块没有做任何事情来处理问题),但您继续执行代码,就好像什么都没发生一样?这会激增代码的复杂性,意味着如果一件事出错,就会出现 85 个异常,除了其中一个之外,其他所有异常都完全不相关。
右边的 'I dunno and I do not care' 捕获块是:throw new RuntimeException("Uncaught", e);
。更新您的 IDE。更好的是,只需抛出 SQLException 即可。例如psv main()
可以(而且应该!)用 throws Exception
声明。更好的应用程序,更少的代码。双赢。
- 您没有应用 try-with-resources。资源(代表实际资源的对象,除了您的机器有多少 RAM 之外,这些资源在其他方面是有限的,例如文件句柄、网络套接字,或者,是的,数据库连接)必须关闭。代码退出的原因有很多——您可以
return
,也可以抛出异常。 try-with-resources 是解决方案。永远不要创建 ResultSet、(Prepared)Statement 或 Connection,除非你这样做:
try (ResultSet rs = ....) {
}
try 的意思是:如果代码退出 {}
,以任何方式(return/break/continue,只是 运行 它的结尾,或异常),在 rs
第一。
如果不这样做,则意味着这些连接会一直挂起,很快数据库引擎就会崩溃并死掉。
- 您正在将密码明文存储在数据库中。如果你作为一家中型公司这样做,你会被罚款几百万美元。我假设您不是这里的公司,但您可能至少要评论说这永远不会超过 'for personal use / just to learn' 阶段。使用 mysql 自己的用户管理(因此,该密码是连接本身的密码),或者使用密码特定的哈希方案,例如 bcrypt。您可以在网络上搜索 'java bcrypt' 了解更多信息。
连接很昂贵,有一些工具可以帮助维护一组连接并在它们之间建立池,重新利用一组打开的连接而不是每次都创建一个新连接。
如果您不想或不能使用这些工具中的一种,至少您可以考虑创建一个连接并在整个过程的生命周期中使用同一个连接。
我更喜欢让像 Hibernate 这样的 ORM 来处理这个,但你可以使用数据源并自己实现它。
检查此 link 以了解稍后的操作:
https://www.baeldung.com/java-connection-pooling
我的程序包含许多 classes,其中一半使用 MySQL 数据库。现在,我为每个 class 单调乏味地连接到 MySQL。我知道这是一个坏习惯,我知道这是一团糟,这就是为什么我想知道是否有一种方法可以一次性连接 class。不过,我不确定如何将此连接传递给 classes。和使用参数类似,还是完全不同?
如果有人需要参考,这里是我的一些 classes:
import ~~~
public class LoginVerify {
public LoginVerify() {
String url = "jdbc:mysql://localhost:3306/grades";
String username = "root";
String password = "root";
JPasswordField jpf = new JPasswordField(10);
JLabel jl = new JLabel("Password: ");
jl.setFont(new Font("Times New Roman", Font.PLAIN, 15));
JTextField username1 = new JTextField(10);
JLabel label = new JLabel("Username: ");
label.setFont(new Font("Times New Roman", Font.PLAIN, 15));
final JButton okay = new JButton("Ok");
okay.setBackground(Color.WHITE);
okay.setFont(new Font("Times New Roman", Font.PLAIN, 15));
final JButton cancel = new JButton("Cancel");
cancel.setBackground(Color.WHITE);
cancel.setFont(new Font("Times New Roman", Font.PLAIN, 15));
Object[] message = {
label, username1,
jl, jpf,
};
int value = JOptionPane.showOptionDialog(
null,
message,
"LOGIN",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
new Object[]{okay, cancel},
okay);
if (value == 0) {
String user = username1.getText();
char[] p = jpf.getPassword();
String pswrd = String.valueOf(p);
System.out.println("user: " + user);
System.out.println("password: " + pswrd);
// CONNECTION STARTS HERE
try {
Connection connection = DriverManager.getConnection(url, username, password);
System.out.println("connection success!!");
String sql = "SELECT * FROM user_info WHERE user_id = ? && user_password = ?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, user);
statement.setString(2, pswrd);
ResultSet rs = statement.executeQuery();
while(rs.next()){
String name = rs.getString("user_name");
System.out.println(name);
new UserMain(user, name, password, null);
}
ResultSet rows = statement.executeQuery();
if (!rows.next() ) {
JLabel l = new JLabel("Username or password incorrect, please try again.");
l.setFont(new Font("Times New Roman", Font.PLAIN, 15));
l.setHorizontalAlignment(SwingConstants.CENTER);
JOptionPane.showMessageDialog(null, l, "ERROR", JOptionPane.PLAIN_MESSAGE);
new LoginVerify();
}
} catch (SQLException e) {
System.out.println("& i oop");
e.printStackTrace();
}
} else if (value == 1) {
JOptionPane.getRootFrame().dispose();
} else System.exit(0);
return;
}
}
你问的其实很复杂。作为一般规则,您 而不是 想要在不相关的代码位之间进行紧密绑定,因此从表面上看,'reuse the connection' 是一个可怕的想法。
不幸的是,数据库连接非常繁重,您也不想一秒钟创建大量的连接。
因此,解决方案是一个令人费解的混乱局面。按说,'convoluted mess'应该先让你走:真的吗?这个问题还没解决?但是,这是大多数情况下没有的情况之一。不过有很好的解决方法。
连接池
你要找的是一个叫做 DB 连接池库的东西。
这些库为您提供了一个 API 接入点,可以让您建立连接。完成后,您不会关闭它,而是将其交还(有时通过关闭它来完成 - 但随后您使用的库将为您提供代理连接,并且在代理上调用 close() 并不是真的关闭它,它只是将它标记为可供下一个调用者使用。
真正复杂的原因是你可以对连接做各种有状态的事情(例如,使用mysql的SET
命令,你可以改变一大堆奇怪的事情持续整个连接),并且连接通常会在一段时间后被数据库引擎破坏,所以仅仅给代码一个池中的连接是不够的 - 你需要 'test' 如果它仍然 'works'首先,运行 一大堆 SET 语句或以其他方式撤消先前使用该连接的代码造成的任何损坏。
那,而且,你想要一个限制器:如果已经有 10 个到同一个数据库的连接仍在进行中,那么对 'get a connection' 的调用应该只是阻塞并等待其中一个10 个已在进行中的连接将交回池中。
这 非常 太多的方面,作为新手一天就搞定了。
因此,获得一个漂亮的、预先编写的开源库来完成所有这些工作。或者,接受你每次都只是建立一个连接,让数据库引擎为它操心。您当然可以获取建立新连接的代码并将其粘贴在某个地方的静态方法中,然后调用它。现在你至少只有一个地方可以编辑 JDBC URL 等等。
那里的首选连接池是 HikariCP。
您的代码有缺陷
- 永远不要通过 'print stack trace and keep going' 处理异常。根据定义,您不知道发生了什么(显然是这样——您的 catch 块没有做任何事情来处理问题),但您继续执行代码,就好像什么都没发生一样?这会激增代码的复杂性,意味着如果一件事出错,就会出现 85 个异常,除了其中一个之外,其他所有异常都完全不相关。
右边的 'I dunno and I do not care' 捕获块是:throw new RuntimeException("Uncaught", e);
。更新您的 IDE。更好的是,只需抛出 SQLException 即可。例如psv main()
可以(而且应该!)用 throws Exception
声明。更好的应用程序,更少的代码。双赢。
- 您没有应用 try-with-resources。资源(代表实际资源的对象,除了您的机器有多少 RAM 之外,这些资源在其他方面是有限的,例如文件句柄、网络套接字,或者,是的,数据库连接)必须关闭。代码退出的原因有很多——您可以
return
,也可以抛出异常。 try-with-resources 是解决方案。永远不要创建 ResultSet、(Prepared)Statement 或 Connection,除非你这样做:
try (ResultSet rs = ....) {
}
try 的意思是:如果代码退出 {}
,以任何方式(return/break/continue,只是 运行 它的结尾,或异常),在 rs
第一。
如果不这样做,则意味着这些连接会一直挂起,很快数据库引擎就会崩溃并死掉。
- 您正在将密码明文存储在数据库中。如果你作为一家中型公司这样做,你会被罚款几百万美元。我假设您不是这里的公司,但您可能至少要评论说这永远不会超过 'for personal use / just to learn' 阶段。使用 mysql 自己的用户管理(因此,该密码是连接本身的密码),或者使用密码特定的哈希方案,例如 bcrypt。您可以在网络上搜索 'java bcrypt' 了解更多信息。
连接很昂贵,有一些工具可以帮助维护一组连接并在它们之间建立池,重新利用一组打开的连接而不是每次都创建一个新连接。
如果您不想或不能使用这些工具中的一种,至少您可以考虑创建一个连接并在整个过程的生命周期中使用同一个连接。
我更喜欢让像 Hibernate 这样的 ORM 来处理这个,但你可以使用数据源并自己实现它。
检查此 link 以了解稍后的操作: https://www.baeldung.com/java-connection-pooling