如果你不喜欢用Hibernate、Mybaits这类ORM框架,喜欢JdbcTemplate或DbUtils,那么可以试试这个封装的通用dal,这可能是目前封装的最方便易用的通用dal层了。
dexcoder-dal的一些特性:
一个dao即可以搞定所有的实体类,不必再一个个建立跟实体对应的继承于类似BaseDao这类“通用dao”了。
各类方法参数除了Entity外,支持更强大的Criteria方式。
sql的where条件支持一些复杂的条件,如等于、不等于、or、in、not in甚至是执行函数。
允许在查询时指定使用哪个字段进行排序,可以指定多个进行组合升降序自由排序。
支持在查询时指定返回字段的白名单和黑名单,可以指定只返回某些字段或不返回某些字段。
select查询时支持函数,count()、max()、to_char()、甚至是distinct,理论上都可以支持。
方便强大的分页功能,无须额外操作,二三行代码搞定分页,自动判断数据库,无须指定。
可以使用{}和[]完成一些特殊的操作,{}中的代码将原生执行,[]中的代码会进行命名转换,一般fieldName转columnName。
支持执行自定义sql。
支持使用类似mybatis的方式执行自定义sql。
支持读写分离和动态数据源。
该通用dao是在使用过程中,针对常规的泛型dao经常遇到的一些不便问题进行了改进。命名上遵循了约定优于配置的原则,典型约定如下:
表名约定USER_INFO表实体类名为UserInfo。
字段名约定USER_NAME实体类中属性名为userName。
主键名约定USER_INFO表主键名为USER_INFO_ID,同理实体类中属性名为userInfoId。
Oracle序列名约定USER_INFO表对应的主键序列名为SEQ_USER_INFO
当然,这些你可以在扩展中改变它,但不建议这么做,这本身就是一个良好的规范。
要在项目中使用通用dao十分简单,目前已上maven中央库,直接在pom.xml中添加依赖:
<dependency> <groupId>com.dexcoder</groupId> <artifactId>dexcoder-dal-spring</artifactId> <version>2.2.0-beta1</version> </dependency>
然后在spring的配置文件中声明如下bean:
<bean id="jdbcDao" class="com.dexcoder.dal.spring.JdbcDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <!--需要分页时声明--> <bean id="pageControl" class="com.dexcoder.dal.spring.page.PageControl"></bean>
接下来就可以注入到您的Service或者其它类中使用了。
先来看一下User对象及它继承的Pageable
public class User extends Pageable { private Long userId; private String loginName; private String password; private Integer userAge; private String userType; private String email; private Date gmtCreate; //...... }
Pageable对象,用来保存页码、每页条数信息以支持分页
public class Pageable implements Serializable { /** 每页显示条数 */ protected int itemsPerPage = 20; /** 当前页码 */ protected int curPage = 1; //...... }
都是普通的JavaBean对象,下面来看看如何进行具体的增删改查,每种操作都演示了Entity和Criteria两种方式。
public void insert() { User user = new User(); user.setLoginName("selfly_a"); user.setPassword("123456"); user.setEmail("javaer@live.com"); user.setUserAge(18); user.setUserType("1"); user.setGmtCreate(new Date()); Long id = jdbcDao.insert(user); System.out.println("insert:" + id); } public void insert2() { Criteria criteria = Criteria.insert(User.class).into("loginName", "selfly_b").into("password", "12345678") .into("email", "selflly@foxmail.com").into("userAge", 22).into("userType", "2").into("gmtCreate", new Date()); Long id = jdbcDao.insert(criteria); System.out.println("insert:" + id); }
public void save() { User user = new User(); user.setUserId(-1L); user.setLoginName("selfly-1"); user.setPassword("123456"); user.setEmail("javaer@live.com"); user.setUserAge(18); user.setUserType("1"); user.setGmtCreate(new Date()); jdbcDao.save(user); } public void save2() { Criteria criteria = Criteria.insert(User.class).into("userId", -2L).into("loginName", "selfly-2") .into("password", "12345678").into("email", "selflly@foxmail.com").into("userAge", 22).into("userType", "2") .into("gmtCreate", new Date()); jdbcDao.save(criteria); }
public void update() { User user = new User(); user.setUserId(57L); user.setPassword("abcdef"); user.setGmtModify(new Date()); jdbcDao.update(user); } public void update2() { Criteria criteria = Criteria.update(User.class).set("password", "update222") .where("userId", new Object[] { 56L, -1L, -2L }); jdbcDao.update(criteria); }
public void get1() { User u = jdbcDao.get(User.class, 63L); Assert.assertNotNull(u); System.out.println(u.getUserId() + " " + u.getLoginName() + " " + u.getUserType()); } public void get2() { //criteria,主要用来指定字段白名单、黑名单等 Criteria criteria = Criteria.select(User.class).include("loginName"); User u = jdbcDao.get(criteria, 73L); Assert.assertNotNull(u); System.out.println(u.getUserId() + " " + u.getLoginName() + " " + u.getUserType()); }
public void delete() { //会把不为空的属性做为where条件 User u = new User(); u.setLoginName("selfly-1"); u.setUserType("1"); jdbcDao.delete(u); } public void delete2() { //where条件使用了or Criteria criteria = Criteria.delete(User.class).where("loginName", new Object[] { "liyd2" }) .or("userAge", new Object[]{64}); jdbcDao.delete(criteria); } public void delete3() { //根据主键 jdbcDao.delete(User.class, 57L); }
public void queryList() { //所有结果 List<User> users = jdbcDao.queryList(User.class); } public void queryList1() { //以不为空的属性作为查询条件 User u = new User(); u.setUserType("1"); List<User> users = jdbcDao.queryList(u); } public void queryList2() { //Criteria方式 Criteria criteria = Criteria.select(User.class).exclude("userId") .where("loginName", new Object[]{"liyd"}); List<User> users = jdbcDao.queryList(criteria); } public void queryList3() { //使用了like,可以换成!=、in、not in等 Criteria criteria = Criteria.select(User.class).where("loginName", "like", new Object[] { "%liyd%" }); user.setUserAge(16); //这里entity跟criteria方式混合使用了,建议少用 List<User> users = jdbcDao.queryList(user, criteria.include("userId")); }
public void queryCount() { user.setUserName("liyd"); int count = jdbcDao.queryCount(user); } public void queryCount2() { Criteria criteria = Criteria.select(User.class).where("loginName", new Object[] { "liyd" }) .or("userAge", new Object[]{27}); int count = jdbcDao.queryCount(criteria); }
public void querySingleResult() { user = jdbcDao.querySingleResult(user); } public void querySingleResult2() { Criteria criteria = Criteria.select(User.class).where("loginName", new Object[] { "liyd" }) .and("userId", new Object[]{23L}); User u = jdbcDao.querySingleResult(criteria); }
public void get(){ //将只返回userName Criteria criteria = Criteria.select(User.class).include("loginName"); User u = jdbcDao.get(criteria, 23L); }
public void get4(){ //将不返回loginName Criteria criteria = Criteria.select(User.class).exclude("loginName"); User u = jdbcDao.get(criteria, 23L); }
public void queryList() { //指定多个排序字段,asc、desc Criteria criteria = Criteria.select(User.class).exclude("userId") .where("loginName", new Object[]{"liyd"}).asc("userId").desc("userAge"); List<User> users = jdbcDao.queryList(criteria); }
public void queryList1() { //进行分页 PageControl.performPage(user); //分页后该方法即返回null,由PageControl中获取 jdbcDao.queryList(user); Pager pager = PageControl.getPager(); //列表 List<User> users = pager.getList(User.class); //总记录数 int itemsTotal = pager.getItemsTotal(); } public void queryList2() { //直接传入页码和每页条数 PageControl.performPage(1, 10); //使用Criteria方式,并指定排序字段方式为asc Criteria criteria = Criteria.select(User.class).include("loginName", "userId") .where("loginName", new Object[]{"liyd"}).asc("userId"); jdbcDao.queryList(criteria); Pager pager = PageControl.getPager(); }
Criteria criteria = Criteria.select(User.class) .where("userType", new Object[] { "1" }).begin() .and("loginName", new Object[] { "selfly" }) .or("email", new Object[] { "javaer@live.com" }).end() .and("password", new Object[] { "123456" }); User user = jdbcDao.querySingleResult(criteria);
//max() Criteria criteria = Criteria.select(User.class).addSelectFunc("max([userId])"); Long userId = jdbcDao.queryForObject(criteria); //count() Criteria criteria = Criteria.select(User.class).addSelectFunc("count(*)"); Long count = jdbcDao.queryForObject(criteria); //distinct Criteria criteria = Criteria.select(User.class).addSelectFunc("distinct [loginName]"); List<Map<String, Object>> mapList = jdbcDao.queryForList(criteria);
默认情况下,addSelectFunc方法返回结果和表字段互斥,并且没有排序,如果需要和表其它字段一起返回并使用排序,可以使用如下代码:
Criteria criteria = Criteria.select(User.class).addSelectFunc("DATE_FORMAT(gmt_create,'%Y-%m-%d %h:%i:%s') date",false,true); List<Map<String, Object>> mapList = jdbcDao.queryForList(criteria);
这是在select中执行函数,那怎么在update和where条件中执行函数呢?前面提到的{}和[]就可以起到作用了。
看下面代码:
Criteria criteria = Criteria.update(User.class).set("[userAge]", "[userAge]+1") .where("userId", new Object[] { 56L }); jdbcDao.update(criteria);
以上代码将执行sql:UPDATE USER SET USER_AGE = USER_AGE+1 WHERE USER_ID = ?,[]中的fieldName被转换成了columnName,
也可以使用{}直接写columnName,因为在{}中的内容都是不做任何操作原生执行的,下面代码效果是一样的:
Criteria criteria = Criteria.update(User.class).set("{USER_AGE}", "{USER_AGE + 1}") .where("userId", new Object[] { 56L }); jdbcDao.update(criteria);
同理,在where中也可以使用该方式来执行函数:
Criteria criteria = Criteria.select(User.class).where("[gmtCreate]", ">", new Object[] { "str_to_date('2015-10-1','%Y-%m-%d')" }); List<User> userList = jdbcDao.queryList(criteria);
有些时候,就算单表操作也必须用到表别名,例如oracle中的xmltype类型。可以在Criteria中设置表别名:
Criteria criteria = Criteria.select(Table.class).tableAlias("t").addSelectFunc("[xmlFile].getclobval() xmlFile") .where("tableId", new Object[]{10000002L}); Object obj = jdbcDao.queryForObject(criteria); //对应的sql select t.XML_FILE.getclobval() xmlFile from TABLE t where t.TABLE_ID = ?
在实际的应用中,一些复杂的查询如联表查询、子查询等是省不了的。鉴于这类sql的复杂性和所需要的各类优化,通用dao并没有直接封装而是提供了执行自定义sql的接口。
执行自定义sql支持两种方式:直接传sql执行和mybatis方式执行。
该方式可能会让除了dao层之外的业务层出现sql代码,因此是不推荐的,它适合一些不在项目中的情况。
何为不在项目中的情况?例如做一个开发自用的小工具,临时处理一批业务数据等这类后期不需要维护的代码。
要执行自定义sql首先需要在jdbcDao中注入sqlFactory,这里使用SimpleSqlFactory:
<bean id="jdbcDao" class="com.dexcoder.dal.spring.JdbcDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> <property name="sqlFactory" ref="sqlFactory"/> </bean> <bean id="sqlFactory" class="com.dexcoder.dal.SimpleSqlFactory"> </bean>
然后就可以直接传入sql执行了:
List<Map<String, Object>> list = jdbcDao.queryForSql("select * from USER where login_name = ?", new Object[] { "selfly_a99" });
这个实现比较简单,参数Object数组中不支持复杂的自定义对象。
采用了插件式实现,使用该方式首先添加依赖:
<dependency> <groupId>com.dexcoder</groupId> <artifactId>dexcoder-dal-batis</artifactId> <version>2.2.0-beta1</version> </dependency>
之后同样注入sqlFactory,把上面的SimpleSqlFactory替换成BatisSqlFactoryBean:
<bean id="jdbcDao" class="com.dexcoder.dal.spring.JdbcDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> <property name="sqlFactory" ref="sqlFactory"/> </bean> <bean id="sqlFactory" class="com.dexcoder.dal.batis.BatisSqlFactoryBean"> <property name="sqlLocation" value="user-sql.xml"/> </bean>
BatisSqlFactoryBean有一个sqlLocation属性,指定自定义的sql文件,因为使用了spring的解析方式,所以可以和指定spring配置文件时一样使用各类通配符。
user-sql.xml是一个和mybatis的mapper类似的xml文件:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//dexcoder.com//DTD Mapper 2.0//EN" "http://www.dexcoder.com/dtd/batis-mapper.dtd"> <mapper namespace="User"> <sql id="columns"> user_id,login_name,password,user_age,user_type </sql> <select id="getUser"> select <include refid="columns"/> from user <where> <if test="params[0] != null"> user_type = #{params[0].userType} </if> <if test="params[1] != null"> and login_name in <foreach collection="params[1]" index="index" item="item" separator="," open="(" close=")"> #{item} </foreach> </if> </where> </select> </mapper>
然后使用代码调用:
User user = new User(); user.setUserType("1"); Object[] names = new Object[] { "selfly_a93", "selfly_a94", "selfly_a95" }; List<Map<String, Object>> mapList = jdbcDao.queryForSql("User.getUser", "params", new Object[] { user, names }); for (Map<String, Object> map : mapList) { System.out.println(map.get("userId")); System.out.println(map.get("loginName")); }
我们调用queryForSql方法时传入了三个参数:
User.getUser 具体的sql全id,namespace+id。
params 自定义sql中访问参数的key,如果不传入默认为item。
Object[] sql中用到的参数。访问具体参数时可以使用item[0],item[1]对应里面相应的元素,支持复杂对象。
可以看到这里支持复杂参数,第一个是Userbean对象,第二个是Object数组,至于获取方式可以看上面的xml代码。
除了传入的参数为Object数组并使用item[0]这种方式访问相应的元素外,其它的和mybatis可以说是一样的,mybatis支持的动态sql方式这里也可以支持,因为他本身就是来源于mybatis。
另外返回结果中map的key做了LOGIN_NAME到骆驼命名法loginName的转换。
BatisSqlFactory方式由分析了mybatis源码后,提取使用了大量mybatis的代码。
JdbcDao在声明时可以根据需要注入其它几个参数:
<bean id="jdbcDao" class="com.dexcoder.dal.spring.JdbcDaoImpl"> <property name="jdbcTemplate" ref="jdbcTemplate"/> <property name="sqlFactory" ref="..."/> <property name="nameHandler" ref="..."/> <property name="rowMapperClass" value="..."/> <property name="dialect" value="..."/> </bean>
nameHandler 默认使用DefaultNameHandler,即遵守上面的约定优于配置,如果需要自定义可以实现该接口。
sqlFactory 执行自定义sql时注入相应的sqlFactory。
rowMapperClass 默认使用了spring的BeanPropertyRowMapper.newInstance(clazz),需要自定义可以自行实现,标准spring的RowMapper实现即可。
dialect 数据库方言,为空会自动判断,一般不需要注入。
Name Description byte 8-bit signed int ubyte 8-bit unsigned int short 16-bit signed int, little-endian ushort 16-bit unsigned int, little-endian int 32-bit signed int, little-endian uint 32-bit unsign
参考:http://www.oschina.net/p/dexcoder-dal 只需添加依赖: <dependency> <groupId>com.dexcoder</groupId> <artifactId>dexcoder-dal-spring</artifactId> <version>2.2.0-beta1</version> </dependency>添加bea
DAO(Data Access Object)侧重ORM对象关系映射,DAO曾往往提供的是ORM操作。 DAL(Data Access Layer)多用于分布式系统 分布式系统提供水平伸缩能力,应用层水平扩展后,会使数据库连接资源相对较少成为瓶颈,此时需要对数据库分库、分表,DAL要求支持透明分库分表,DAL层提供的往往是sql 仅为个人见解。
问题内容: 我是PHP和SQL领域的一名新开发人员。到目前为止,我只完成了Objective- C编程。但是,我的一个项目要求我拥有一个在线数据库,我需要从我的应用程序访问该数据库。我打算使用该框架来远程访问数据库,如下所示: 但这是行不通的,因为我联系了我的托管服务提供商,并且他们已经对其进行了设置,因此我无法从外部主机访问我的数据库(出于安全性考虑)。因此,我将不得不寻找替代方案。我唯一想到的
ActiveX Data Objects (ADO) 是一项容易使用并且可扩展的将数据库访问添加到 Web 页的技术。可以使用 ADO 去编写紧凑简明的脚本以便连接到 Open Database Connectivity (ODBC) 兼容的数据库和 OLE DB 兼容的数据源。如果您是一个对数据库连接有一定了解的脚本编写人员,那么您将发现 ADO 命令语句并不复杂而且容易掌握。同样地,如果您是一
对许多Web应用程序而言,数据库都是其核心所在。数据库几乎可以用来存储你想查询和修改的任何信息,比如用户信息、产品目录或者新闻列表等。 Go没有内置的驱动支持任何的数据库,但是Go定义了database/sql接口,用户可以基于驱动接口开发相应数据库的驱动,5.1小节里面介绍Go设计的一些驱动,介绍Go是如何设计数据库驱动接口的。5.2至5.4小节介绍目前使用的比较多的一些关系型数据驱动以及如何使
程序运行的时候,数据都是在内存中的。当程序终止的时候,通常都需要将数据保存到磁盘上,无论是保存到本地磁盘,还是通过网络保存到服务器上,最终都会将数据写入磁盘文件。 而如何定义数据的存储格式就是一个大问题。如果我们自己来定义存储格式,比如保存一个班级所有学生的成绩单: 名字 成绩 Michael 99 Bob 85 Bart 59 Lisa 87 你可以用一个文本文件保存,一行保存一个学生,用,隔开
程序运行的时候,数据都是在内存中的。当程序终止的时候,通常都需要将数据保存到磁盘上,无论是保存到本地磁盘,还是通过网络保存到服务器上,最终都会将数据写入磁盘文件。 而如何定义数据的存储格式就是一个大问题。如果我们自己来定义存储格式,比如保存一个班级所有学生的成绩单: 名字 成绩 Michael 99 Bob 85 Bart 59 Lisa 87 你可以用一个文本文件保存,一行保存一个学生,用,隔开
主要内容:ADO.Net对象模型,数据提供者,数据集(DataSet),连接到数据库,示例1,示例3应用程序与数据库进行通信,首先检索存储在数据库中的数据,并以便于用户使用的方式显示;其次,通过插入,修改和删除数据来更新数据库中的数据。 Microsoft ActiveX Data Objects.Net(ADO.Net)是一个模型,是.NET应用程序用于检索,访问和更新数据的.Net框架的一部分。 ADO.Net对象模型 ADO.Net对象模型不过是通过各种组件的结构化流程流程。对象模型可以描