【问题标题】:What is the difference between JDBC and JDBI?JDBC和JDBI有什么区别?
【发布时间】:2011-08-14 17:35:07
【问题描述】:

我想知道JDBCJDBI在java中的区别。特别是,一般来说哪一个更好,为什么?

【问题讨论】:

  • 请定义“更好”。
  • 这个比较很奇怪。而是将 JDBI 与 Hibernate、JPA、Datanucleus、JDO 等进行比较。
  • JDBI 更容易使用。如果您对完全使用 ORM 有点警惕但厌倦了可怕的糟糕 JDBC API,那么值得学习。

标签: java jdbc jdbi


【解决方案1】:

你的意思是https://jdbi.org

jDBI 旨在在 Java(tm) 中提供方便的表格数据访问。它使用 Java 集合框架来查询结果,提供一种方便的外部化 sql 语句的方法,并为正在使用的任何数据库提供命名参数支持。

JDBI使用JDBC,如果不知道是否需要JDBI,建议不要使用。

【讨论】:

  • 没有人需要 JDBI——它是JDBC上的一个便利层。它使得在 SQL 中而不是通过更多抽象库与数据库进行通信变得更加方便。
【解决方案2】:

就像已经回答的大多数人一样,JDBI 是在JDBC 之上的一个便利库,它对大多数应用程序的用户友好性并不高,而且过于底层。

根据我的个人经验,JDBI 位于成熟的 ORM 和自己动手的 JDBC 之间。也就是说,我相信通过在控制(您可以轻松调整 SQL)和便利(与JDBC 相比,您的工作效率显着提高)之间取得平衡,它涵盖了普通开发人员可能需要的 95%。

当然,一张图片胜过千言万语。这是一个 DAO 方法,通过JDBI 获取一行并将其转换为对象层次结构:

   @Override
    public Widget fetchWidget(String widgetGuid) {
        Widget widget = jdbi.withHandle(
            handle ->  {
                return handle.createQuery(
                    "SELECT guid, x AS p_x, y AS p_y, width, height, zindex FROM widget WHERE guid = :widgetGuid"
                ).bind("widgetGuid", widgetGuid)
                .registerRowMapper(ConstructorMapper.factory(Widget.class))
                .mapTo(Widget.class)
                .one();
            }
        );
        return widget;
    }

想象一下,用JDBC 做同样的事情 - 可行,但很乏味......而JDBI 可以做的远不止这些 - 例如,检查它的SqlObject API。

【讨论】:

    【解决方案3】:

    (我是jDBI的主要作者)

    jDBI 是一个建立在JDBC 之上的便利库。 JDBC 工作得很好,但通常似乎针对用户的数据库供应商(驱动程序编写者)进行了优化。 jDBI 尝试公开相同的功能,但在为用户优化的 API 中。

    它比HibernateJPA 之类的级别低得多。最接近的类似库可能是MyBatisiBATIS 的分叉继承者)。

    jDBI 支持两种样式 API,一种较旧的 fluent 样式,如下所示:

    List<Something> r = h.createQuery("select * from something where name = :name and id = :id")
                    .bind(0, "eric")
                    .bind("id", 1)
                    .map(Something.class)
                    .list();
    

    较新的 SQL 对象 API 做了更多反射类型的东西,并且确实开始抽象一堆 JDBC 的东西:

    interface TheBasics
    {
        @SqlUpdate("insert into something (id, name) values (:id, :name)")
        int insert(@BindBean Something something);
    
        @SqlQuery("select id, name from something where id = :id")
        Something findById(@Bind("id") long id);
    }
    
    @Test
    public void useTheBasics() throws Exception
    {
        TheBasics dao = dbi.onDemand(TheBasics.class);
    
        dao.insert(new Something(7, "Martin"));
    
        Something martin = dao.findById(7);
    }
    

    该库在http://jdbi.org/ 上有很好的参考文档 (javadoc) 和一些合理的教程样式文档。它自 2004 年以来一直存在,并且被相对少数人使用(我个人认识的几十个人,可能还有十几家公司),但对他们来说效果很好。大多数从事它工作的人都是 A+ 人员,主要关心的是构建一个适合他们的工具——它是开源的,这在很大程度上是一种副作用。

    【讨论】:

    • 我发现对 JDBI 的补充非常有用:gitlab.com/rbertoncelj/jdbi-entity-mapper。它的类很少,但在模型中添加了@Column,所以我可以映射例如fullName 字段到 full_name 列。它也存在于 Maven 中。你有没有想过在你的项目中加入这个功能?
    • 另一个可能有用的插件:一个实体 ORM,它增加了对创建/保存/删除和最常见的 DAO 方法(例如Person.dao.count())的支持:gitlab.com/mvysny/jdbi-orm
    【解决方案4】:

    确实,JDBI 是建立在 JDBC 之上的,实际上,您很可能会使用 JDBC 来访问 DB,而 JDBI 将包含(或包装)JDBC 以针对 DB 执行 PreparedStatements。

    在内部,JDBC 驱动程序是执行事务的驱动程序,JDBI 只是充当中介。

    它比 ORM(如 Hibernate 或 Spring)更轻巧,但它确实有助于加快开发速度并拥有更多“漂亮和干净”的东西,因为它有很多实用程序可以使编码更容易和更清洁,例如:

    要定义一个简单的对象来插入/读取一个表,你可以这样做:

    import com.sql.poc.data.jDBI.map.AgentMapper;
    import com.sql.poc.domain.Agent;
    import org.skife.jdbi.v2.sqlobject.Bind;
    import org.skife.jdbi.v2.sqlobject.SqlQuery;
    import org.skife.jdbi.v2.sqlobject.SqlUpdate;
    import org.skife.jdbi.v2.sqlobject.customizers.Mapper;
    import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
    
    public interface SqlObjectDataAccess extends Transactional<SqlObjectDataAccess> {
    
        @SqlUpdate("INSERT INTO pocAgent (LocationId, Name, Country) VALUES (:id, :name, :country)")
        void insertAgent(@Bind("id") String locationId,
                         @Bind("name") String name,
                         @Bind("country") String country);
    
        @SqlQuery("SELECT LOCATIONID, NAME, COUNTRY, CREATEDON FROM pocAgent WHERE LOCATIONID = :LocationId")
        @Mapper(AgentMapper.class)
        Agent getAgentByLocation(@Bind("LocationId") String locationId);
    
        void close();    
    }
    

    JDBI 让您可以将所有映射逻辑放在同一个位置,例如:

    import com.sql.poc.domain.Agent;
    import org.skife.jdbi.v2.StatementContext;
    import org.skife.jdbi.v2.tweak.ResultSetMapper;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class AgentMapper implements ResultSetMapper<Agent> {
        @Override
        public Agent map(int index, ResultSet r, StatementContext ctx) throws SQLException {
            return new Agent(r.getString("LocationId"),
                    r.getString("Name"),
                    r.getString("Country"),
                    r.getDate("CreatedOn"));
        }
    }
    

    然后你只需要使用DAO(数据访问对象):

    import com.google.inject.Inject;
    import com.sql.poc.IConnectionHelper;
    import com.sql.poc.domain.Agent;
    import org.skife.jdbi.v2.DBI;
    import org.skife.jdbi.v2.logging.Log4JLog;
    
    public class SqlObjectRepository {
        IConnectionHelper _connectionHelper;
        DBI _dbiInstance;
        SqlObjectDataAccess _daoHandler;
    
        @Inject
        SqlObjectRepository() {
            _dbiInstance = new DBI(_connectionHelper.getDataSource());
            _dbiInstance.setSQLLog(new Log4JLog());
        }
    
        public void openConnection() {
            if (_daoHandler == null)
                _daoHandler = _dbiInstance.open(SqlObjectDataAccess.class);
        }
    
        @org.skife.jdbi.v2.sqlobject.Transaction
        public Agent insertAgent(String locationId, String name, String country) {
            openConnection();
            Agent agent = _daoHandler.getAgentByLocation(locationId);
            if (agent == null) {
                _daoHandler.insertAgent(locationId, name, country);
            }
            agent = _daoHandler.getAgentByLocation(locationId);
            _daoHandler.commit();
            return agent;
        }
    }
    

    然后,如果我们再深入一点,检查如何连接到 DB,您会注意到,对于这个概念证明示例,使用了 JDBC:

    import com.google.inject.Inject;
    import com.sql.poc.IConnectionHelper;
    import org.apache.commons.dbcp.ConnectionFactory;
    import org.apache.commons.dbcp.DriverManagerConnectionFactory;
    import org.apache.commons.dbcp.PoolableConnectionFactory;
    import org.apache.commons.dbcp.PoolingDataSource;
    import org.apache.commons.pool.impl.GenericObjectPool;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    
    public class TandemMPConnectionHelper implements IConnectionHelper {
        private final DataSource _dataSource;
    
        @Inject
        TandemMPConnectionHelper() {
            try {
                Class.forName("com.tandem.t4jdbc.SQLMXDriver");
            } catch (ClassNotFoundException e) {
                System.out.println(e.toString());
            }
            _dataSource = setupDataSource("jdbc:t4sqlmx://<server>:<port>/:<username>:<password>:", "user1", "password1");
        }
    
        @Override
        public DataSource setupDataSource(String connectURI, String userName, String password) {
            GenericObjectPool connectionPool = new GenericObjectPool();
            connectionPool.setMaxActive(20);
            ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(
                    connectURI,
                    userName,
                    password);
            new PoolableConnectionFactory(connectionFactory, connectionPool, null, null, false, false);
            return new PoolingDataSource(connectionPool);
        }
    
        @Override
        public DataSource getDataSource() {
            return _dataSource;
        }
    
        @Override
        public Connection getConnection() {
            Connection connection;
            try {
                connection = _dataSource.getConnection();
                connection.setAutoCommit(false);
            } catch (SQLException e) {
                System.out.println(e.getMessage());
                return null;
            }
            return connection;
        }
    }
    

    在这种情况下,我访问的是 Tandem Non/Stop 数据库,但同样适用于 SQL Server、ORACLE 或您访问的任何数据库,您只需要正确的 JDBC 驱动程序(您可以找到很容易,只需谷歌它!)。

    希望它能让您更清楚地了解,从概念上讲,JDBI 和 JDBC 在代码中的位置。

    【讨论】:

      【解决方案5】:

      我在搜索命名 SQL 参数时找到了 jDBI。我使用已知的竞争对手 Spring JDBC NamedTemplate,但对 8-10MB 有奇怪的依赖关系。我已经依赖于 ANTLR。

      我看了几个小时,jDBI 似乎很鼓舞人心。 两者(jDBI/Spring JDBC)都可以在某种程度上与 iBatis/MyBatis 等轻量级 ORM 进行比较。

      【讨论】:

        【解决方案6】:

        jDBI 建立在 JDBC 之上。所有 Java 应用程序都使用 JDBC 来访问关系数据库,因此这不是非此即彼的选择。他们是免费的。没有 JDBC 就不能使用 jDBI。

        话虽如此,jDBI 是另一个人试图将 Java 开发人员从 JDBC 所需的样板文件中解脱出来的尝试。这就像选择 Hibernate 或 TopLink 或 iBatis。

        【讨论】:

          【解决方案7】:

          JDBC 是 Java 中用于访问 SQL 数据库的一个历史悠久的标准。 DB 供应商实现了 JDBC 驱动程序,以便可以以统一的方式访问所有 DB。几乎所有使用 Java 数据库完成的事情都使用 JDBC。

          JDBI 似乎是 JDBC 之上的某种抽象层,但很难说清楚,因为它的文档很少。它当然没有被广泛使用,这是我第一次听说它。

          【讨论】:

          • 文档确实很少,但老实说,与原始 JDBC 相比,它让生活更轻松;没有像 Hibernate 这样的 ORM 解决方案的所有复杂性和不透明性(这可能是也可能不是问题——ORM 对于许多用例来说都很棒)。无论如何,除了项目主页上的简单 jdbi 文档外,还有这个博客条目 (cowtowncoder.com/blog/archives/2010/04/entry_391.html) 可能对介绍使用基础知识很有用。
          • 最好从 JDBC 入手,以深入了解 DB 连接和处理结果,或者选择更成熟的框架,这些框架具有强大的社区支持和文档(例如 Hibernate、Spring-JDBC)。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-10-16
          • 2017-05-19
          • 2015-11-24
          • 1970-01-01
          • 2014-11-21
          • 2010-10-02
          • 2011-12-12
          相关资源
          最近更新 更多