【发布时间】:2011-08-14 17:35:07
【问题描述】:
【问题讨论】:
-
请定义“更好”。
-
这个比较很奇怪。而是将 JDBI 与 Hibernate、JPA、Datanucleus、JDO 等进行比较。
-
JDBI 更容易使用。如果您对完全使用 ORM 有点警惕但厌倦了可怕的糟糕 JDBC API,那么值得学习。
【问题讨论】:
你的意思是https://jdbi.org?
jDBI 旨在在 Java(tm) 中提供方便的表格数据访问。它使用 Java 集合框架来查询结果,提供一种方便的外部化 sql 语句的方法,并为正在使用的任何数据库提供命名参数支持。
JDBI使用JDBC,如果不知道是否需要JDBI,建议不要使用。
【讨论】:
就像已经回答的大多数人一样,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。
【讨论】:
(我是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+ 人员,主要关心的是构建一个适合他们的工具——它是开源的,这在很大程度上是一种副作用。
【讨论】:
@Column,所以我可以映射例如fullName 字段到 full_name 列。它也存在于 Maven 中。你有没有想过在你的项目中加入这个功能?
Person.dao.count())的支持:gitlab.com/mvysny/jdbi-orm
确实,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 在代码中的位置。
【讨论】:
我在搜索命名 SQL 参数时找到了 jDBI。我使用已知的竞争对手 Spring JDBC NamedTemplate,但对 8-10MB 有奇怪的依赖关系。我已经依赖于 ANTLR。
我看了几个小时,jDBI 似乎很鼓舞人心。 两者(jDBI/Spring JDBC)都可以在某种程度上与 iBatis/MyBatis 等轻量级 ORM 进行比较。
【讨论】:
jDBI 建立在 JDBC 之上。所有 Java 应用程序都使用 JDBC 来访问关系数据库,因此这不是非此即彼的选择。他们是免费的。没有 JDBC 就不能使用 jDBI。
话虽如此,jDBI 是另一个人试图将 Java 开发人员从 JDBC 所需的样板文件中解脱出来的尝试。这就像选择 Hibernate 或 TopLink 或 iBatis。
【讨论】:
JDBC 是 Java 中用于访问 SQL 数据库的一个历史悠久的标准。 DB 供应商实现了 JDBC 驱动程序,以便可以以统一的方式访问所有 DB。几乎所有使用 Java 数据库完成的事情都使用 JDBC。
JDBI 似乎是 JDBC 之上的某种抽象层,但很难说清楚,因为它的文档很少。它当然没有被广泛使用,这是我第一次听说它。
【讨论】: