7 回答
(我是jDBI的主要作者)
jDBI是一个建立在JDBC之上的便利库。JDBC 工作得很好,但通常似乎针对用户的数据库供应商(驱动程序编写者)进行了优化。jDBI 尝试公开相同的功能,但在为用户优化的 API 中。
它比Hibernate或JPA低得多。最接近的类似库可能是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+ 人,主要关心的是构建一个适合他们的工具——它是开源的,这在很大程度上是一个副作用。
你的意思是https://jdbi.org吗?
jDBI 旨在在 Java(tm) 中提供方便的表格数据访问。它使用 Java 集合框架来查询结果,提供一种方便的外部化 sql 语句的方法,并为正在使用的任何数据库提供命名参数支持。
JDBI 使用的是 JDBC,如果你不知道是否需要 JDBI,我建议你不要使用它。
JDBC 是 Java 中用于访问 SQL 数据库的一个历史悠久的标准。DB 供应商实现了 JDBC 驱动程序,以便可以以统一的方式访问所有 DB。几乎所有在 Java 中使用数据库完成的事情都使用 JDBC。
JDBI 似乎是 JDBC 之上的某种抽象层,但很难说清楚,因为它的文档很少。它当然没有被广泛使用,这是我第一次听说它。
jDBI 建立在 JDBC 之上。所有 Java 应用程序都使用 JDBC 来访问关系数据库,因此这不是非此即彼的选择。他们是免费的。没有 JDBC 就不能使用 jDBI。
话虽如此,jDBI 是另一个人试图将 Java 开发人员从 JDBC 所需的样板文件中解脱出来的尝试。这就像选择 Hibernate 或 TopLink 或 iBatis。
实际上,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 的位置。
就像大多数已经回答过的人一样,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。
当我搜索命名 SQL 参数时,我发现了 jDBI。我使用已知的竞争对手 Spring JDBC NamedTemplate,但对 8-10MB 有奇怪的依赖关系。我已经依赖于 ANTLR。
我看了几个小时,jDBI 似乎很鼓舞人心。两者(jDBI/Spring JDBC)都可以在某种程度上与 iBatis/MyBatis 等轻量级 ORM 进行比较。