52

我想知道java中JDBCJDBI的区别。特别是,哪一个通常更好,为什么?

4

7 回答 7

119

(我是jDBI的主要作者)

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

它比HibernateJPA低得多。最接近的类似库可能是MyBatis ( iBATIS的分叉继承者)。

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+ 人,主要关心的是构建一个适合他们的工具——它是开源的,这在很大程度上是一个副作用。

于 2011-06-06T22:36:00.463 回答
9

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

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

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

于 2011-04-28T13:37:30.273 回答
8

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

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

于 2011-04-28T13:39:47.797 回答
5

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

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

于 2011-04-28T14:27:54.120 回答
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;
    }
}

然后,如果我们再深入一点,检查如何连接到数据库,您会注意到,对于这个概念证明示例,使用了 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 的位置。

于 2015-04-23T15:09:13.447 回答
1

就像大多数已经回答过的人一样,JDBI它是一个便利库,在它之上JDBC不是特别用户友好,并且对于大多数应用程序来说过于低级。

根据我的个人经验,JDBI它位于成熟的 ORM 和自己动手的 JDBC 之间。也就是说,我相信它涵盖了普通开发人员可能需要的 95% 的内容,方法是在控制(您可以轻松调整 SQL)和便利性(与JDBC.

当然,一张图片胜过一千个字。这是一个 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。

于 2019-12-09T14:52:58.787 回答
0

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

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

于 2012-05-18T08:13:11.133 回答