【问题标题】:should a db connection be a singleton?数据库连接应该是单例吗?
【发布时间】:2011-09-24 08:40:12
【问题描述】:

在 Java 中创建单例的最佳方法是什么? 数据库连接应该是单例(作为单例,它是自动线程安全的)吗?因为理论上数据库不能被多个用户同时访问。

【问题讨论】:

  • 谁告诉你如果某个东西是单例的,它会自动成为线程安全的?此外,数据库通常由许多用户同时访问。
  • @Reverend Gonzo 有没有线程安全的单身人士?
  • 单例只是一个对象,它只创建一个实例。它与对象的线程安全无关。如果该对象的内部不是线程安全的,则将其转换为单例不会使其成为线程安全的。 Connection 对象不是线程安全的,因为您不能从多个线程同时使用它。通过使其成为单例,如果您尝试从多个线程访问该连接,则很容易出现严重问题。 (您应该使用的是连接池(通过库或 ThreadLocal)以使每个线程有一个连接。

标签: java design-patterns singleton


【解决方案1】:

Java 中最好的创建方式是什么 单身?

遵循设计模式创建指南。即私有构造函数等。

数据库连接是否应该是单例的 (作为单身人士,它会自动 线程安全)?

在许多情况下,将数据库连接创建为单例可能是一个糟糕的设计选择。仅当您确定不需要数据库并发时才使用它。如果您有多个用户同时登录,或者即使您的单个用户产生了许多需要访问数据库的线程,那么数据库连接池是更好的选择。您可以使用 apache 或 tomcat db 连接池。例如,这些类在包中定义

org.apache.commons.dbcp.*;

org.apache.tomcat.dbcp.dbcp.*;

其中 dbcp 代表数据库连接池。

使用连接池的最大原因是平均而言,访问数据库(DML 等)所需的时间远小于创建连接然后关闭连接所需的时间。此外,不要忘记在事务完成后关闭您的 ResultSet、PreparedStatement 和 Connection 变量。

因为理论上数据库不可能 多个用户同时访问 时间。

为什么不呢?在大多数情况下,DB 意味着要同时使用。您有这些数据库隔离级别 - READ_COMMITTED、READ_UNCOMMITTED、SERIALIZED 等。 SERIALIZED 是您的数据库成为单用户访问的情况。

【讨论】:

    【解决方案2】:

    数据库连接通常不应是单例。

    两个原因:

    1. 许多数据库驱动程序不是线程安全的。使用单例意味着如果你有很多线程,它们都将共享同一个连接。单例模式不会给你线程安全。它只是允许多个线程轻松共享一个“全局”实例。
    2. 就个人而言,我认为 Singleton 经常会导致糟糕的设计:请参阅此帖子(由其他人撰写)http://tech.puredanger.com/2007/07/03/pattern-hate-singleton/

    考虑一个数据库池,而不是这样做。池是共享的(如果您愿意,可以是单例)。当你需要做数据库工作时,你的代码会这样做:

    getConnectioFromPool();
    
    doWork()
    closeConnection() // releases back to pool
    

    示例池库:

    【讨论】:

    • 如果连接器不是Singletone,是否应该在ServletContext中上传DB连接器?会是好的OOP风格吗?
    • 我通常使用 spring 将池化数据源注入到我的对象中。如果应用服务器支持,池化数据源可以来自 JNDI,或者在 spring 本身中定义一个数据源。
    • 一般这几点是非常有效的;但是,有一些数据库,例如 MongoDB,设计人员特别推荐了 Singleton 模式,并且一些数据库确实保证了线程安全。基本上,阅读您的数据库的规格并考虑应用程序......
    • 当你有一个没有真正线程的应用程序时,我认为将单例用于全局资源并不是那么糟糕,例如python 或 dart 应用程序。
    【解决方案3】:

    创建单例的最佳方法是枚举单例模式 (Java enum singleton)

    我怀疑单例对于数据库连接是否必要或任何价值。您可能想要一些惰性创建:在第一次请求时创建连接并缓存,进一步的请求将被缓存的实例填充:

    public ConnectionProvider {
      private Connection conn;
    
      public static Connection getConnection() {
        if (conn == null || conn.isClosed()) {
          conn = magicallyCreateNewConnection();
        }
        return conn;
      }
    }
    

    (不是线程安全的 - 同步,如果需要)

    【讨论】:

    • 是的,Singleton 不是 Connection 对象的好选择。但是,是否应该创建一个由数据库池支持的单例数据源?
    【解决方案4】:

    Singleton 是一种模式 - 没有明确的创建方法,您只需遵循设计实践即可。

    因此,如果您使用的是可以处理并发读/写的数据库(即 MySQL),则无需过多担心线程安全。如果您使用的数据库不能很好地进行并发写入(SQLite),那么理论上单例应该可以工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多