JDBC和JDBI有什么区别?

时间:2011-04-28 13:29:29

标签: java jdbc jdbi

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

7 个答案:

答案 0 :(得分:88)

(我是jDBI的主要作者)

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

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

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

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 Object 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);
}

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

答案 1 :(得分:8)

您的意思是http://jdbi.codehaus.org/吗?

  

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

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

答案 2 :(得分:7)

JDBC是Java中用于访问SQL数据库的长期标准。数据库供应商实现JDBC驱动程序,以便可以以统一的方式访问所有数据库。实际上,Java中的数据库所做的一切都使用了JDBC。

JDBI似乎是JDBC之上的某种抽象层,但由于文档记录很少,因此很难说。它肯定没有被广泛使用,这是我第一次听说它。

答案 3 :(得分:5)

jDBI构建于JDBC之上。所有Java应用程序都使用JDBC来访问关系数据库,因此它不是一种选择。他们是免费的。没有JDBC就不能使用jDBI。

据说,jDBI是另一个尝试从Java所需的样板中解脱Java开发人员的尝试。这就像选择Hibernate或TopLink或iBatis。

答案 4 :(得分:4)

实际上,JDBI是建立在JDBC之上的,实际上,很可能你会使用JDBC来访问数据库,JDBI将是包含(或包装)JDBC以获取针对数据库执行PreparedStatements的数据。

在内部,JDBC驱动程序是执行事务的驱动程序,JDBI只是作为中介使用。

它比ORM(如Hibernate或Spring)更轻,但它确实有助于加速开发并拥有更多的东西,并且#34;漂亮而干净&#34;,因为它有很多实用程序使编码更容易和更清洁,例如:

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

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;
    }
}

然后,如果我们更深入一点,并检查连接是如何对数据库进行的,您会注意到,对于此Proof of Concept示例,使用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驱动程序(你可以轻松找到,只需Google吧!)。

希望它能让您更清楚地了解在代码中将JDBI和JDBC定位在哪里。

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

就像大多数人已经回答的那样,JDBIJDBC之上的便利库,它不是特别友好,并且对于大多数应用程序来说太底层了。

从我的个人经验来看,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。