文档章节

基于 Java 的 Active Record 开源项目

黄勇
 黄勇
发布于 2014/05/23 02:05
字数 5039
阅读 6344
收藏 143

Active Record 是什么?也许很多做 Java 的朋友并没有听说过这个概念,但它确实很早就已经出现了。

确切地说,应该是在 2003 年,由世界大师级人物 Martin Fowler(马丁 · 福勒)在他写的一本叫做《企业应用架构模式》书里就描述过这个模式。不可否认,马丁是软件架构的泰斗,他写的每本书,我都买过,虽然很多内容我还看不懂,但每次阅读都有新的认识,虽然这些文字已经很陈旧了。

如果您想了解关于 Active Record 的权威定义,可以点击下面的维基百科地址:

http://zh.wikipedia.org/wiki/Active_Record

当然,如果您想听到更通俗易懂的言语,我可以试着描述一下:

  1. 它是面向领域对象的设计模式
  2. 它为每个领域对象提供一组 CRUD 方法

以上提到的 领域对象 实际上就是我们经常说的 Entity(实体)。

Active Record 模式最早是在 Ruby on Rails(RoR)里取得了最佳实践,然后其它开发语言开始效仿,比如:PHP、Python 等,当然 Java 也不例外。

这几天我收集了几款基于 Java 的 Active Record 开源项目,这些项目都非常优秀,让我收获良多、受益匪浅!所以我忍不住想与大家分享一下我的学习心得与体会。

需要申明的是:本文仅代表个人看法,本人仅站在使用者的角度来体验这些产品,并非对技术架构与实现进行评价,若大家有不同见解,欢迎讨论!

下面的这些 Active Record 框架的排名不分先后,但我还是想给出一个“推荐指数”(满分是 5 颗星),当然这仅代表我个人的观点。

为了描述方便,以下将 Active Record 简称为 AR

JFinal(国产)

JFinal 是国内最流行的轻量级 Java Web 框架之一,作者深厚的功力,让我敬佩万分!今天也是我第一次评价 JFinal,当然仅作为一名用户,对该框架的 AR 使用方面发表一点个人观点。

我们不妨先看看在 JFinal 中是怎样使用 AR 的吧:

<!-- lang: java -->
// 创建name属性为James,age属性为25的User对象并添加到数据库
new User().set("name", "James").set("age", 25).save();

// 删除id值为25的User
User.dao.deleteById(25);

// 查询id值为25的User将其name属性改为James并更新到数据库
User.dao.findById(25).set("name", "James").update();

// 查询id值为25的user, 且仅仅取name与age两个字段的值
User user = User.dao.findById(25, "name, age");

// 获取user的name属性
String userName = user.getStr("name");

// 获取user的age属性
Integer userAge = user.getInt("age");

// 查询所有年龄大于18岁的user
List<User> users = User.dao.find("select * from user where age > 18");

// 分页查询sex为1并且年龄大于18的user,当前页号为1,每页10个user
Page<User> userPage = User.dao.paginate(1, 10, "select *", "from user where sex=? and age>?", 1, 18);

可见,代码还是非常精辟的,面向 User 实体,通过访问该实体的 dao 成员变量来调用相关 AR 方法,非常不错!

尤其是这种链式方法,简直太棒了!

<!-- lang: java -->
new User().set("name", "James").set("age", 25).save();

此外,该框架还提供了一个 Db + Record 的开发模式,无需编写任何的实体就能完成数据库操作。我很喜欢,很赞!

最新的 1.6 版本也支持了多数据源,也就是说,在 AR 中可以同时使用 MySQL 与 Oracle 数据库,这是两个不同的数据源。这个特性也非常好!相信一定很受欢迎。

但作为用户而言,我还是想提几点在编码过程中一点点太完美的地方,当然只是吹毛求疵了。

首先,以上代码中的 set 方法里的 key 是 User 的属性名,假如需要将 name 重命名,那么势必会修改很多相关的代码,否则如果有一个漏掉了,就容易出现 Bug,也就是说,当重构时会有风险。

然后,我们来看看以下这行代码:

<!-- lang: java -->
User.dao.findById(25)

我认为,如果能这样写会更加精简:

<!-- lang: java -->
User.find(25)

也就是说,把 dao 去掉,并且简化方法名,默认就是根据 id 来获取实体对象。

下面我大致总结一下:

亮点:

  • 链式方法调用,例如:new User().set("name", "James").set("age", 25).save()
  • 无需编写实体即可操作数据库,例如:提供 Record、Db 这些实用类
  • 支持多数据源,例如:在 find 时可指定 mysql 或 oracle

瑕疵:

  • 通过字符串来操作实体属性,当重构时会有风险,例如:user.set("name", "James")
  • API 不够简洁,例如:User.dao.findById(25) 方法,不妨可简化为:User.find(25)
  • 分页方法过于繁琐,例如:将 select 语句划分为两段,形成了两个参数

参考:

推荐指数:★ ★ ★

ar4j

这个框架是一个老外写的,我对它并不是太熟悉,只是从文档上大致学习了一下。

比较有特色的是,实体类无需扩展任何类,只需实现一个该框架提供的名为 ActiveRecord<T> 的泛型接口,我们需要将具体的 Entity 类型太填充这个泛型。就像这样:

<!-- lang: java -->
public abstract class Primary implements ActiveRecord<Primary> {
    ...
}

这里定义了一个名为 Primary 的实体类,实现了 ActiveRecord<Primary> 接口,此外,将该类设置为 abstract 的,因为无需在代码中 new 这个对象。

下面我们看看该框架是如何实现 find 操作的:

<!-- lang: java -->
IActiveRecordFactory factory = NamedSingletonActiveRecordFactory.getFactory();
Primary instance = factory.getActiveRecord(Primary.class);
instance.getContext().setDataSource(dataSource);

Map<String, Object> firstParameters = new HashMap<String, Object>();
firstParameters.put("code", "FIRST_PRIMARY");
Collection<Primary> firstResults = instance.find(firstParameters);

首先,我们得初始化一个 IActiveRecordFactory 工厂(接口),然后使用该工厂去获取相应的 AR 实例,也就是这里的 Primary 实体对象了。

然后,通过构造一个 Map,来填充查询条件,貌似这里的每个查询条件都是 and 的关系。

最后,携带那个 Map 参数来调用 Primary 实体对象的 find 方法,从而获取相应的集合对象。

这种方式感觉有些保守,从代码上来看,写得太多,不太优雅。说实话,我个人不太喜欢。

需要提醒大家的是,该框架在 2010 年就停止维护了,考虑使用该框架的同学需要想想了。

不管怎么说,还是要总结一下的:

亮点:

  • 实体无需扩展任何类,只需实现一个 ActiveRecord<T> 接口
  • 支持自定义数据类型转换
  • 方便与 Spring 集成

瑕疵:

  • 创建 Record 对象不太直接,需要借助 Factory 类
  • find 方法的参数过于繁琐,针对查询条件与分页参数
  • 不支持 OneToMany 等特性

参考:

推荐指数:★ ★

jActiveRecord(国产)

这个框架我是在 OSC Git 上发现的,当初是被它的 readme 文档所吸引,写得非常简洁,新手能在较短的时间内入门。

该框架为用户提供了三个实用类,分别是:DBTableRecord,可想而知,这三个类分别对应:数据库、表、记录,这样的定义方式让人非常容易接受,至少学过关系型数据库的同学们都知道这三个概念。

我们再来简单看看它的用法:

连接数据库:

<!-- lang: java -->
DB sqlite3 = DB.open("jdbc:sqlite::memory:");

添加:

<!-- lang: java -->
Table Zombie = sqlite3.active("zombies");
Zombie.create("name:", "Ash", "graveyard:", "Glen Haven Memorial Cemetery");
Zombie.create("name", "Bob", "graveyard", "Chapel Hill Cemetery");
Zombie.create("graveyard", "My Fathers Basement", "name", "Jim");

查询:

<!-- lang: java -->
Record jim = Zombie.find(3);
int id = jim.get("id");
String name = jim.get("name");
Timestamp createdAt = jim.get("created_at");

更新:

<!-- lang: java -->
Record jim = Zombie.find(3);
jim.set("graveyard", "Benny Hills Memorial").save();
jim.update("graveyard:", "Benny Hills Memorial");

删除:

<!-- lang: java -->
Zombie.find(1).destroy();
Zombie.delete(Zombie.find(1));

关联:

<!-- lang: java -->
Zombie.hasMany("tweets").by("zombie_id");
Tweet.belongsTo("zombie").by("zombie_id").in("zombies");

Record jim = Zombie.find(3);
Table jimTweets = jim.get("tweets");
for (Record tweet : jimTweets.all()) {
  ...
}

可见,代码可读性还是挺高的,而且也非常容易理解,这说明作者在 API 的设计上还是花了点功夫的,非常不错!

还支持多种实体之间的关联,绝对是有一定技术含量的,所以这一定是该框架的一大亮点。

该框架非常活跃,从 OSC Git 上观察到,最近作者提交过代码。

正所谓“人无完人”,对于框架也不例外,下面便是我对该框架的总结:

亮点:

  • 仅提供 DB、Table、Record 三个实用类,就能操作数据库
  • 支持多种数据库:MySQL、PostgreSQL、HyperSQL、SQLite
  • 支持一对多、多对一、多对多等关联

瑕疵:

  • 不支持 Oracle 数据库,需要自行扩展
  • 通过字符串来操作实体属性,当重构时会有风险
  • 需要通过 API 的手工方式来建立关联,不具备自动方式

参考:

推荐指数:★ ★ ★ ★

etmvc(国产)

其实我很早就关注过 etmvc 框架,因为它是一款轻量级 Java Web 开发框架。在该框架中,我学到了很多宝贵的经验,非常感谢作者的贡献与分享!

说起该框架的作者,也许大家非常熟悉,他就是著名的 jQuery Easy UI 的创始人,能把 Java 与 JS 玩得如此棒的人,我都非常地佩服,膜拜一下!

需要的是,对于 AR 而言,只是该框架中的一部分,但这部分绝对给它增加了不少分数。

还是先看看具体的使用方法吧:

首先,我们需要定义一个实体类:

<!-- lang: java -->
@Table(name="users")
public class User extends ActiveRecordBase{
    @Id private Integer id;
    @Column private String name;
    @Column private String addr;
    @Column private String email;
    @Column private String remark;
    //get,set...
}

需要注意的是,User 实体必须继承框架提供的 ActiveRecordBase 父类,这样才能拥有相关的 AR 方法。

然后,我们再来看看具体的 CRUD 操作:

插入:

<!-- lang: java -->
User user = new User();
user.setName("name1");
user.setAddr("addr1");
user.setEmail("name1@gmail.com");
user.save();

更新:

<!-- lang: java -->
User user = User.find(User.class, 3);
user.setRemark("user remark");
user.save();

删除:

<!-- lang: java -->
User user = User.find(User.class, 3);
user.destroy();

查询:

<!-- lang: java -->
List<User> users = User.findAll(User.class);
for(User user: users){
    System.out.println(user.getName());
}

多条件查询:

<!-- lang: java -->
List<User> users = User.findAll(User.class, "addr like ?", new Object[]{"%百花路%"});
for(User user: users){
    System.out.println(user.getName());
}

但貌似与 JFinal 存在类似的问题,那就是 find 方法用起来有些繁琐,比如:

<!-- lang: java -->
User user = User.find(User.class, 3);

如果能这样写就更加漂亮了:

<!-- lang: java -->
User user = User.find(3);

也就是说,find 方法里的第一个参数 User.class 是多余的,因为 find 方法已经是 User 类中的 static 方法了,是有办法获取 User.class 的。

与 JFinal 相同,多数据源在该框架中也是支持的。

此外,还提供了编程式事务,但框架自身没有提供声明式事务的支持。

有点特色的还有,可以在实体类上配置注解,来支持多种关联,相信用过 Hibernate 的同学一定不会感到陌生。

这个框架目前也不再维护了,最新版本的发布时间是 2009 年 12 月,虽然该框架真的非常优秀,但我还是要建议大家谨慎使用。

来对它总结一下吧:

亮点:

  • 支持多数据源
  • 使用类似注解来配置关联,支持一对多、一对一、多对一等
  • 支持回调方法

瑕疵:

  • find 方法不够简洁,例如:User.find(User.class, 3),不妨可简化为:User.find(3)
  • 不支持多对多关联
  • 仅支持编程式事务控制,不支持声明式或基于注解的配置

参考:

推荐指数:★ ★ ★ ★

ActiveJDBC

说起 ActiveJDBC,想必有些人听说过,因为该框架是最早开始用 Java 实现 AR 模式的,可以号称 Java 界里第一个吃 AR 这只螃蟹的人。

因为做得比较久了,项目得到了很好的沉淀,功能相当之多,建议大家可以看看它的官方文档。

有点特色的是,无需编写任何的实体属性,而只需继承一个框架提供的 Model 类即可。下面是一个实例类:

<!-- lang: java -->
public class Person extends Model {}

该框架可以自动扫描数据库的表结构,通过字节码增强的方式来修改实体类的 class 文件。

尤其是这样的链式方法,我个人是非常喜欢的:

<!-- lang: java -->
List<person> people = Person.where("name = ?", "John");
Person aJohn = people.get(0);
String johnsLastName = aJohn.get("last_name");
Paging through data
List<employee> people = Employee.where("department = ? and hire_date > ? ", "IT", hireDate)
    .offset(21)
    .limit(10)
    .orderBy("hire_date asc");

无需担心不同数据库的分页 SQL 语句的差异性了。

该框架的功能较多,特点也非常多,我还是简单总结一下吧:

亮点:

  • 无需编写任何的实体属性,只需继承一个 Model 父类,由框架来扫描数据库表结构,生成实体属性与关联
  • 提供链式的 find 方法调用,尤其是编写分页代码时非常优雅
  • 可使用注解定义缓存

瑕疵:

  • 通过字符串来操作实体属性,当重构时会有风险
  • 在实体上进行执行 SQL 查询,有些不太合适
  • 对于多对多关联,需要为中间表编写对应的实体类(Hibernate 不需要这样做)

参考:

推荐指数:★ ★ ★ ★

ActiveObjects

我是在 Google 里得知 ActiveObjects 这个开源项目的,貌似以前火了一段时间,至少在互联网上可以找到关于它的博文。

但让我非常理解的是,为何该框架官网也打不开?貌似作者不再维护了。更让我惊讶的是,我在 Atlassian 的开源项目中看到了该框架。可以推论出,该框架已经纳入 Atlassian 的体系架构了。

不知道算不算亮点,该框架竟然将实体定义为接口,而不是类。下面是一个实体接口:

<!-- lang: java -->
public interface Company extends Entity {
    // ...
}

这个接口需要继承框架提供的 Entity 接口。那么实体属性如何定义呢?

<!-- lang: java -->
public interface Company extends Entity {

    public String getName();
    public void setName(String name);
    
    public String getTickerSymbol();
    public void setTickerSymbol(String tickerSymbol);
}

看到以上这样的代码,我第一反应是,这些代码需要手写了,因为 IDE 几乎没办法自动生成这些 getter/setter 方法。

我们再来看看具体怎么用?

<!-- lang: java -->
EntityManager manager = new EntityManager("jdbc:mysql://localhost/test", "user", "password");
Company[] companies = manager.find(Company.class);

首先,我们需要创建一个 EntityManager 对象,然后,通过该对象去 find 出相应的实体数组。

这类风格好不好呢?反正我个人是不喜欢的。

说实话,我很少关注 Atlassian 的开源项目,他们的商业产品,比如:JIRA、Confluence 等,我还是非常喜爱的(尤其是破解版)。

亮点:

  • 将实体定义为接口,自身继承一个名为 Entity 的接口
  • 通过基于 Query 类的链式方法生成 SQL 语句
  • 支持自定义 ORM 映射规则

瑕疵:

  • 在实体接口中没有属性,只有属性的 getter/setter 方法,无法通过 IDE 自动生成
  • 查询操作均通过 EntityManager 来完成,与 ActiveRecord 的传统风格不太一致
  • 项目已归入 Atlassian 名下,成为 Atlassian Platform Common Components 的一部分

参考:

推荐指数:★ ★

Ebean

Ebean 是一位朋友推荐给我的,曾经听说过,但并没有关注过,一直认为它是一个小众框架。当我静下心来学习之后,才发现该框架真所谓“麻雀虽小,五脏俱全”啊!

有点类似于精简版的 Hibernate,它基于 JPA 接口,提供了根据实体自动生成 DDL 的功能,可以借助 Spring 强大的事务管理机制。总而言之,该框架我很喜欢!

要使用该框架,必须提供一个 ebean.properties 配置文件,做简单的配置即可使用,相应的配置请参考官方文档(见下面的参考部分)。

我们看看如何来插入一条记录?

<!-- lang: java -->
ESimple e = new ESimple();  
e.setName("test");  
e.setDescription("something");  
Ebean.save(e);  

通过 Ebean 这个实用类就能完成,这里不太像其他 AR 框架那样,直接在实体 ESimple 上调用 save 方法。不知道这算不算严格意义上的 AR 呢?

对于查询而言,同样也是面向 Ebean 类的:

<!-- lang: java -->
List<Order> list = Ebean.find(Order.class).findList(); 

以上代码貌似还可以再简洁一下,比如:

<!-- lang: java -->
List<Order> list = Ebean.findList(Order.class);

这样是不是更好呢?我认为没必要先调用 find 方法。

该项目最近(2014 年 4 月)才发布了 3.3.1 版本,可见还有是非常有生命力的。

稍微归纳一下吧:

亮点:

  • 基于 JPA 规范,依赖于 persistence.jar
  • 可以通过实体生成 DDL,类似于 Hibernate
  • 支持类似 Spring 的事务传播行为,并且能与 Spring 无缝集成

瑕疵:

  • find 方法不够简洁,例如:Ebean.find(Order.class).findList(),不妨可简化为:Ebean.findList(Order.class)
  • 链式风格的查询条件不太适合复杂情况,对于复杂的情况需要使用类似 SQL 的查询语言
  • 通过字符串硬编码的方式来连接查询,当重构时会有风险

参考:

推荐指数:★ ★ ★ ★

jOOQ

jOOQ 同样也是一位朋友推荐的,我花了一点时间学习了一下。发现学习成本不高,还是比较容易上手的。官网做得很漂亮,文档也非常丰富!

使用该框架,我们需要先定义数据库表结构,然后就是配置,最后该框架提供了一个代码生成器,我们只需通过 java 命令就能运行该代码生成器,最终为我们生成实体类 Java 源码。与 Hibernate 的使用过程正好相反,Hibernate 要求我们先定义实体类,然后通过实体类来生成数据库表结构。

对于用户而言,只需使用该框架提供的 API 即可完成底层的 SQL 操作,而无需编写具体的 SQL 代码。就像这样:

<!-- lang: java -->
DSLContext create = DSL.using(conn, SQLDialect.MYSQL);
Result<Record> result = create.select().from(AUTHOR).fetch();

我们必须提供一个数据库连接,也就是以上代码中的 conn 参数。第二行代码将执行一条 MySQL 的 SQL 语句:

<!-- lang: sql -->
select * from author;

需要补充说明的是,以上代码中的 AUTHOR 其实是来自于 test.generated.Tables.* 包,所以我们需要使用静态导入。此外,DSL 是来自于 org.jooq.impl.DSL.* 包的,同样需要静态导入。

<!-- lang: java -->
import static test.generated.Tables.*;
import static org.jooq.impl.DSL.*;

下面要做的就是遍历 result 对象了:

<!-- lang: java -->
for (Record r : result) {
    Integer id = r.getValue(AUTHOR.ID);
    String firstName = r.getValue(AUTHOR.FIRST_NAME);
    String lastName = r.getValue(AUTHOR.LAST_NAME);
    System.out.println("ID: " + id + " first name: " + firstName + " last name: " + lastName);
}

看起来貌似挺简单的,实际好不好用呢?那就需要在进一步的实践中慢慢体会了。

还有更复杂的 SQL 语句,都可以通过 Java API 的方式来表达,如下图(来自于官网):

jOOQ

需要指出的是,该框架仅提供基于 Java 代码的 SQL 操作,并没有提供事务管理框架,所以还是需要借助像 Spring 这样的框架来实现。

亮点:

  • 可读取配置扫描数据库,自动生成 Java 代码(与 Hibernate 正好相反)
  • 使用链式方法生成对应方言的 SQL 语句
  • 代码生成器可以定制

瑕疵:

  • 开发人员需要熟知表结构与之间的关系
  • 未提供事务控制,但可集成 Spring 的事务
  • 对于复杂 SQL 查询需要编写大量的 Java 代码

参考:

推荐指数:★ ★ ★ ★

其它

当然,基于 Java 的 AR 框架还有很多,下面补充几个,大家有空可以了解一下:

© 著作权归作者所有

黄勇

黄勇

粉丝 6611
博文 121
码字总数 216155
作品 1
浦东
CTO(技术副总裁)
私信 提问
加载中

评论(29)

k
kewell2004
楼主,User.find(User.class, 3)的第一个参数是为了保持检索结果的灵活性。
圊國圊國
圊國圊國
不喜欢这种模式,个人感觉mybatis那种模式比较好
c
cc12

引用来自“Bieber”的评论

楼主威武,通过这篇文章算算对AR模式有了一定的了解。综合上面几个框架的实现,整体来说实现方案可以分为两类。
1、Entity不可实例化,通过实现或者集成某个接口/抽象类,来对实体进行标识。定义了方法的是通过AOP来实现
2、Entity可实例化,通过集成框架的某个抽象类,来获得AR的功能,进行增删查改。这里用的比较多的是反射,来对类进行解析
综合上面,感觉AR在多表关联,以及实现比较复杂的数据库操作的时候,都比较棘手。
所以说在复杂查询时直接写SQL了,一般ORM都集成原生SQL查询的接口,AR模式在web开发领域应该算是绝对的主流,但是java就是个奇葩.不过java的特色就是这样的,这是它的风格
笑傲软件园
笑傲软件园
这个用来写后台的bactch小程序。还是挺不错的。可以快速完成。
奋斗到天明
奋斗到天明
看来PlayFramework真是没落了……居然提都没人提了……显然JFinal那些缺点,Play都补上了。
水牛叔叔
水牛叔叔
我第一次接触active record 是用thinkphp的时候,那时感觉眼前一亮
softdawn
softdawn
好好学习了
luluback
luluback

引用来自“悠悠然然”的评论

先占个位,呵呵,啥时候有空给TinyDB也加几行说明 。
我简述两行:
干活之前先要获取个DBOperator
DBOperator operator=DbOperatorFactory.getDBOperator("User");//User对应表名user
Bean user=operator.createBean();//创建一个bean对象
user.setProperty("name","abc").setProperty("age",22);//设置其属性
Bean user=operator.getBean(1);//或者从数据库获取一个
operator.insert(user);
operator.update(user);
operator.delete(user);
为什么没有把insert,update,delete放在Bean上呢?原因是在分布式计算中,如果构建了一个Bean对象,调用其insert,delete,update是无效的,因此我把操作独立出来,Bean仅用于描述数据。
TinyDB的设置思路,是No Pojo、No dao方式,也就是说你啥也不用写,直接用就好了。
redraiment
redraiment
感觉楼主推荐`jActiveRecord`,今天发布了2.2版,并发布到Maven中央库;此外,还引入了`jActiveRecord-EL`项目,简化在EL表达式中访问Record的属性:http://git.oschina.net/redraiment/jactiverecord-el
黄勇
黄勇 博主

引用来自“搜索小虫”的评论

请问楼主 你说的“find 方法里的第一个参数 User.class 是多余的,因为 find 方法已经是 User 类中的 static 方法了,是有办法获取 User.class 的。” 是通过什么方法? 这个User类应该是经常父类的,而这个static 方法也来之父类,而且实现也在父类中,那么这个static方法实现的时候,怎么知道User类呢32
如果这个方法是非static 的成员方法您说的是没有错误的。
不妨先看看 ActiveJDBC 的具体用法:http://javalite.io/record_selection
求大神指导tomcat服务器挂掉问题

最近新上线一个功能。但是Tomcat每隔几日就不明不白地挂掉。看了日志也找不出原因: DEBUG - Returning JDBC Connection to DataSource DEBUG - trace com.mchange.v2.resourcepool.BasicRes...

江戸川乱歩
2016/10/10
676
3
微软再发力,正式宣布开源 JDBC 驱动程序

11月17日,微软项目经理 Andrea Lam 在开发者社区地宣布 SQL Server 的 Microsoft JDBC 驱动程序开源。希望通过驱动程序的开源,从社区获得更快的反馈,更快的发布节奏,以及基于 Java 开发人...

王练
2016/11/19
9.2K
24
脱离Rails使用ActiveRecord

ActiveRecord是Ruby的对象-关系映射(ORM)框架,它几乎总是被视为Rails框架的一部分,但其自身也是一个实体,可通过gem单独安装和使用。本文以访问Sqlite3为例,介绍如何在Rails框架之外使用...

redraiment
2014/02/11
1K
2
为什么阿里巴巴禁止在 foreach 循环里进行元素的 remove/add 操作

· Oracle 撒手,宣布对个人用户 (Personal Users) , Java 8 官方支持时间持续到 2020 年 12 月;对商业用户(Commercial Users),2019 年 1 月之后不再提供免费更新。 · 红帽喊话,计划在...

Java填坑路
03/20
154
2
Azul 开源 Zing Jvm

4月末,继Zing 5.2 之后,Azul Systems宣布他们将无停顿(pauseless)的Zing JVM提供给开源软件开发者和项目,以供开发和测试。 Azul Systems 工程部副总裁和合作创始人Shyam Pillalamarri向...

闻术苑
2012/09/10
4.3K
18

没有更多内容

加载失败,请刷新页面

加载更多

64.监控平台介绍 安装zabbix 忘记admin密码

19.1 Linux监控平台介绍 19.2 zabbix监控介绍 19.3/19.4/19.6 安装zabbix 19.5 忘记Admin密码如何做 19.1 Linux监控平台介绍: 常见开源监控软件 ~1.cacti、nagios、zabbix、smokeping、ope...

oschina130111
今天
13
0
当餐饮遇上大数据,嗯真香!

之前去开了一场会,主题是「餐饮领袖新零售峰会」。认真听完了餐饮前辈和新秀们的分享,觉得获益匪浅,把脑子里的核心纪要整理了一下,今天和大家做一个简单的分享,欢迎感兴趣的小伙伴一起交...

数澜科技
今天
7
0
DNS-over-HTTPS 的下一代是 DNS ON BLOCKCHAIN

本文作者:PETER LAI ,是 Diode 的区块链工程师。在进入软件开发领域之前,他主要是在做工商管理相关工作。Peter Lai 也是一位活跃的开源贡献者。目前,他正在与 Diode 团队一起开发基于区块...

红薯
今天
13
0
CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
今天
12
0
实验分析性专业硕士提纲撰写要点

为什么您需要研究论文的提纲? 首先当您进行研究时,您需要聚集许多信息和想法,研究论文提纲可以较好地组织你的想法, 了解您研究资料的流畅度和程度。确保你写作时不会错过任何重要资料以此...

论文辅导员
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部