jOOQ是一个库,可帮助我们重新控制SQL。 它可以从我们的数据库生成代码,并允许我们使用其流畅的API来构建类型安全的数据库查询。

本教程前面的部分向我们介绍了如何配置示例应用程序的应用程序上下文以及如何从数据库中生成代码。

现在,我们已经准备好向前迈出一步,学习如何使用jOOQ创建类型安全查询。 这篇博客文章描述了如何将CRUD操作添加到管理待办事项的简单应用程序中。

让我们开始吧。

补充阅读:

  • 将jOOQ与Spring结合使用:配置是本教程的第一部分,它描述了您可以配置使用jOOQ的Spring应用程序的应用程序上下文。 您可以在不阅读本教程第一部分的情况下了解此博客文章,但是,如果您想在基于Spring的应用程序中真正使用jOOQ,建议您也阅读本教程的第一部分。
  • 将jOOQ与Spring结合使用:代码生成是本教程的第二部分,它描述了我们如何对数据库进行反向工程并创建代表不同数据库表,记录等的jOOQ查询类。 因为这些类是类型安全SQL查询的构建块, 所以建议您在阅读本博客文章之前阅读本教程的第二部分

创建Todo类

让我们从创建一个包含单个待办事项条目信息的类开始。 此类具有以下字段:

  • ID字段包含待办事项的ID。
  • creationTime字段包含一个时间戳,该时间戳描述了todo条目第一次被持久保存的时间。
  • description字段包含待办事项的描述。
  • ModifyTime字段包含一个时间戳,该时间戳描述了待办事项条目的更新时间。
  • 标题字段包含待办事项的标题。

这个相对简单的类的名称为Todo ,它遵循以下三个原则:

  • 我们可以使用Joshua Bloch在Effective Java中描述的构建器模式来创建新的Todo对象。 如果您不熟悉此模式,则应阅读标题为项目2的文章:面对许多构造函数参数时,请考虑使用构建器 。
  • 标题字段是必填字段,我们不能创建标题为空或为空的新Todo对象。 如果尝试创建标题无效的Todo对象,则会抛出IllegalStateException
  • 此类是不可变的。 换句话说,其所有字段都声明为final

Todo类的源代码如下所示:

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.joda.time.LocalDateTime;import java.sql.Timestamp;public class Todo {private final Long id;private final LocalDateTime creationTime;private final String description;private final LocalDateTime modificationTime;private final String title;private Todo(Builder builder) {this.id = builder.id;LocalDateTime creationTime = null;if (builder.creationTime != null) {creationTime = new LocalDateTime(builder.creationTime);}this.creationTime = creationTime;this.description = builder.description;LocalDateTime modificationTime = null;if (builder.modificationTime != null) {modificationTime = new LocalDateTime(builder.modificationTime);}this.modificationTime = modificationTime;this.title = builder.title;}public static Builder getBuilder(String title) {return new Builder(title);}//Getters are omitted for the sake of clarity.public static class Builder {private Long id;private Timestamp creationTime;private String description;private Timestamp modificationTime;private String title;public Builder(String title) {this.title = title;}public Builder description(String description) {this.description = description;return this;}public Builder creationTime(Timestamp creationTime) {this.creationTime = creationTime;return this;}public Builder id(Long id) {this.id = id;return this;}public Builder modificationTime(Timestamp modificationTime) {this.modificationTime = modificationTime;return this;}public Todo build() {Todo created = new Todo(this);String title = created.getTitle();if (title == null || title.length() == 0) {throw new IllegalStateException("title cannot be null or empty");}return created;}}
}

让我们找出为什么我们需要获取当前日期和时间,更重要的是,什么是最好的方法。

获取当前日期和时间

因为每个待办事项的创建时间和修改时间都存储在数据库中,所以我们需要一种获取当前日期和时间的方法。 当然,我们可以简单地在存储库中创建此信息。 问题是,如果这样做,我们将无法编写自动测试来确保正确设置了创建时间和修改时间(我们无法为这些字段编写断言,因为它们的值取决于当前时间) 。

这就是为什么我们需要创建一个单独的组件来负责返回当前日期和时间的原因。 DateTimeService接口声明了以下两种方法:

  • getCurrentDateTime()方法将当前日期和时间作为LocalDateTime对象返回。
  • getCurrentTimestamp()方法将当前日期和时间作为Timestamp对象返回。

DateTimeService接口的源代码如下所示:

import org.joda.time.LocalDateTime;
import java.sql.Timestamp;public interface DateTimeService {public LocalDateTime getCurrentDateTime();public Timestamp getCurrentTimestamp();
}

因为我们的应用程序对“实时”感兴趣,所以我们必须实现此接口并创建一个返回实际日期和时间的组件。 我们可以按照以下步骤进行操作:

  1. 创建一个实现DateTimeService接口的CurrentTimeDateTimeService类。
  2. @Profile注释为类添加注释,并将配置文件的名称设置为“ application”。 这意味着,当活动的Spring配置文件为“应用程序”时,可以将组件注册到Spring容器。
  3. @Component注释对类进行注释。 这样可以确保在类路径扫描期间找到该类。
  4. 实现在DateTimeService接口中声明的方法。 每个方法都必须返回当前日期和时间。

CurrentTimeDateTimeService的源代码如下所示:

import org.joda.time.LocalDateTime;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;import java.sql.Timestamp;@Profile("application")
@Component
public class CurrentTimeDateTimeService implements DateTimeService {@Overridepublic LocalDateTime getCurrentDateTime() {return LocalDateTime.now();}@Overridepublic Timestamp getCurrentTimestamp() {return new Timestamp(System.currentTimeMillis());}
}

让我们继续并开始实现示例应用程序的存储库层。

实施存储库层

首先,我们创建一个存储库接口,该接口为待办事项提供CRUD操作。 该接口声明了以下五种方法:

  • Todo add(Todo todoEntry)方法将新的todo条目保存到数据库中,并返回已保存的todo条目的信息。
  • Todo delete(Long id)方法删除一个待办事项条目并返回删除的待办事项条目。
  • List findAll()方法返回从数据库中找到的所有待办事项条目。
  • Todo findById(Long id)返回单个todo条目的信息。
  • Todo更新(Todo todoEntry)更新待办事项的信息并返回更新后的待办事项。

TodoRepository接口的源代码如下所示:

import java.util.List;public interface TodoRepository {public Todo add(Todo todoEntry);public Todo delete(Long id);public List<Todo> findAll();public Todo findById(Long id);public Todo update(Todo todoEntry);
}

接下来,我们必须实现TodoRepository接口。 当我们这样做时,我们必须遵循以下规则:

jOOQ创建的所有数据库查询都必须在事务内执行 。 原因是我们的应用程序使用TransactionAwareDataSourceProxy类 ,并且如果我们在没有事务的情况下执行数据库查询,则jOOQ将为每个操作使用不同的连接。 这可能会导致竞赛条件错误。

通常,服务层充当事务边界,并且对jOOQ存储库的每次调用都应在事务内部进行。 但是,由于程序员也会犯错误,因此我们不能相信情况确实如此。 这就是为什么我们必须使用@Transactional批注来批注存储库类或其方法。

既然已经了解了这一点,就可以创建存储库类了。

创建存储库类

我们可以按照以下步骤创建存储库类的“骨架”:

  1. 创建一个JOOQTodoRepository类并实现TodoRepository接口。
  2. @Repository批注对类进行批注。 这样可以确保在类路径扫描期间找到该类。
  3. DateTimeService字段添加到创建的类。 我们记得, DateTimeService接口声明用于获取当前日期和时间的方法。
  4. DSLContext字段添加到创建的类。 该接口充当jOOQ API的入口点,我们可以使用它来构建SQL查询。
  5. 将公共构造函数添加到创建的类中,并使用@Autowired注释对构造函数进行注释。 这可以确保通过使用构造函数注入来注入存储库的依赖项。
  6. 将私有的Todo convertQueryResultToModelObject(TodosRecord queryResult)方法添加到存储库类。 此实用程序方法由我们的存储库类的公共方法使用。 通过执行以下步骤来实现此方法:
    1. 通过使用作为方法参数给出的TodosRecord对象的信息来创建新的Todo对象。
    2. 返回创建的对象。

JOOQTodoRepository类的相关部分如下所示:

import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;@Repository
public class JOOQTodoRepository implements TodoRepository {private final DateTimeService dateTimeService;private final DSLContext jooq;@Autowiredpublic JOOQTodoRepository(DateTimeService dateTimeService, DSLContext jooq) {this.dateTimeService = dateTimeService;this.jooq = jooq;}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();}
}

让我们继续并实现为待办事项提供CRUD操作的方法。

添加新的待办事项

TodoRepository接口的公共Todo add(Todo todoEntry)方法用于向数据库添加新的todo条目。 我们可以通过执行以下步骤来实现此方法:

  1. 将一个私有的TodosRecord createRecord(Todo todoEntry)方法添加到存储库类,并按照以下步骤实现此方法:

    1. 通过调用DateTimeService接口的getCurrentTimestamp()方法获取当前日期和时间。
    2. 创建一个新的TodosRecord对象,并使用作为方法参数给出的Todo对象的信息来设置其字段值。
    3. 返回创建的TodosRecord对象。
  2. add()方法添加JOOQTodoRepository类中,并使用@Transactional注释对该方法进行注释。 这样可以确保INSERT语句在读写事务中执行。
  3. 通过执行以下步骤来实现add()方法:
    1. 通过执行以下步骤将新的待办事项条目添加到数据库:

      1. 通过调用DSLContext接口的insertInto(Table table)方法来创建新的INSERT语句,并指定要向todos表中插入信息。
      2. 通过调用createRecord()方法创建一个新的TodosRecord对象。 将Todo对象作为方法参数传递。
      3. 通过调用InsertSetStep接口的set(Record record)方法来设置插入的信息。 将创建的TodosRecord对象作为方法参数传递。
      4. 通过调用InsertReturningStep接口的returning()方法,确保INSERT查询返回所有插入的字段。
      5. 通过调用InsertResultStep接口的fetchOne ()方法,获取包含所有插入字段的值的TodosRecord对象。
    2. 通过调用convertQueryResultToModelObject()方法,将INSERT语句返回的TodosRecord对象转换为Todo对象。
    3. 返回创建的Todo对象。

JOOQTodoRepository类的相关部分如下所示:

import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;import java.sql.Timestamp;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository
public class JOOQTodoRepository implements TodoRepository {private final DateTimeService dateTimeService;private final DSLContext jooq;//The constructor is omitted for the sake of clarity@Transactional@Overridepublic Todo add(Todo todoEntry) {TodosRecord persisted = jooq.insertInto(TODOS).set(createRecord(todoEntry)).returning().fetchOne();return convertQueryResultToModelObject(persisted);}private TodosRecord createRecord(Todo todoEntry) {Timestamp currentTime = dateTimeService.getCurrentTimestamp();TodosRecord record = new TodosRecord();record.setCreationTime(currentTime);record.setDescription(todoEntry.getDescription());record.setModificationTime(currentTime);record.setTitle(todoEntry.getTitle());return record;}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();}
}

4.3.3节。 jOOQ参考手册的INSERT语句提供了有关将数据插入数据库的其他信息。

让我们继续前进,找出如何找到存储在数据库中的所有条目。

查找所有待办事项

TodoRepository接口的公共List findAll()方法返回所有存储在数据库中的待办事项。 我们可以通过执行以下步骤来实现此方法:

  1. findAll()方法添加到存储库类,并使用@Transactional批注对该方法进行批注。 将其readOnly属性的值设置为true 。 这样可以确保SELECT语句在只读事务中执行。
  2. 通过执行以下步骤,从数据库中获取所有待办事项:
    1. 通过调用DSLContext接口的selectFrom(Table table)方法来创建新的SELECT语句,并指定您要从todos表中选择信息。
    2. 通过调用ResultQuery接口的fetchInto(Class type)方法获取TodosRecord对象的列表。
  3. 迭代返回的TodosRecord对象列表,并通过调用convertQueryResultToModelObject()方法将每个TodosRecord对象转换为Todo对象。 每个ToDo对象添加到的Todo对象的列表。
  4. 返回包含找到的Todo对象的列表

JOOQTodoRepository类的相关部分如下所示:

import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;import java.util.ArrayList;
import java.util.List;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository
public class JOOQTodoRepository implements TodoRepository {private final DSLContext jooq;//The constructor is omitted for the sake of clarity@Transactional(readOnly = true)@Overridepublic List<Todo> findAll() {List<Todo> todoEntries = new ArrayList<>();List<TodosRecord> queryResults = jooq.selectFrom(TODOS).fetchInto(TodosRecord.class);for (TodosRecord queryResult: queryResults) {Todo todoEntry = convertQueryResultToModelObject(queryResult);todoEntries.add(todoEntry);}return todoEntries;}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();}
}

4.3.2节。 jOOQ参考手册的SELECT语句提供了有关从数据库中选择信息的更多信息。

接下来,我们将找到如何从数据库中获得一个待办事项。

查找单个待办事项

TodoRepository接口的公共Todo findById(Long id)方法返回单个todo条目的信息。 我们可以通过执行以下步骤来实现此方法:

  1. 在存储库类中添加findById()方法,并使用@Transactional注释对方法进行注释。 将其readOnly属性的值设置为true。 这样可以确保SELECT语句在只读事务中执行。
  2. 通过执行以下步骤,从数据库中获取单个待办事项的信息:
    1. 通过调用DSLContext接口的selectFrom(Table table)方法来创建新的SELECT语句,并指定您要从todos表中选择信息。
    2. 通过调用SelectWhereStep接口的where(Collection condition)方法来指定SELECT语句的WHERE子句。 确保SELECT语句仅返回ID作为方法参数给出的todo条目。
    3. 通过调用ResultQuery接口的fetchOne ()方法来获取TodosRecord对象。
  3. 如果返回的TodosRecord对象为null,则表示未找到具有给定id的todo条目。 在这种情况下,抛出一个新的TodoNotFoundException
  4. 通过调用convertQueryResultToModelObject()方法将SELECT语句返回的TodosRecord对象转换为Todo对象。
  5. 返回创建的Todo对象。

JOOQTodoRepository的相关部分如下所示:

import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository
public class JOOQTodoRepository implements TodoRepository {private final DSLContext jooq;//The constructor is omitted for the sake of clarity.@Transactional(readOnly = true)@Overridepublic Todo findById(Long id) {TodosRecord queryResult = jooq.selectFrom(TODOS).where(TODOS.ID.equal(id)).fetchOne();if (queryResult == null) {throw new TodoNotFoundException("No todo entry found with id: " + id);}return convertQueryResultToModelObject(queryResult);}private Todo convertQueryResultToModelObject(TodosRecord queryResult) {return Todo.getBuilder(queryResult.getTitle()).creationTime(queryResult.getCreationTime()).description(queryResult.getDescription()).id(queryResult.getId()).modificationTime(queryResult.getModificationTime()).build();}
}

4.3.2节。 jOOQ参考手册的SELECT语句提供了有关从数据库中选择信息的更多信息。

让我们找出如何从数据库中删除待办事项。

删除待办事项

TodoRepository接口的公共Todo delete(Long id)方法用于从数据库中删除一个todo条目。 我们可以通过执行以下步骤来实现此方法:

  1. delete()方法添加到存储库类中,并使用@Transactional注释对方法进行注释。 这样可以确保DELETE语句在读写事务中执行。
  2. 通过执行以下步骤来实现此方法:
    1. 通过调用findById(Long id)方法查找已删除的Todo对象。 将已删除的待办事项条目的ID作为方法参数传递。
    2. 通过执行以下步骤从数据库中删除待办事项条目:
      1. 通过调用DSLContext接口的delete(Table table)方法来创建新的DELETE语句,并指定要从todos表中删除信息。
      2. 通过调用DeleteWhereStep接口的where(Collection condition)方法,指定DELETE语句的WHERE子句。 确保DELETE语句删除ID为方法参数的待办事项。
      3. 通过调用Query接口的execute()方法执行 DELETE语句。
    3. 返回已删除的待办事项条目的信息。

JOOQTodoRepository类的相关部分如下所示:

import net.petrikainulainen.spring.jooq.todo.db.tables.records.TodosRecord;
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository
public class JOOQTodoRepository implements TodoRepository {private final DSLContext jooq;//The constructor is omitted for the sake of clarity@Transactional@Overridepublic Todo delete(Long id) {Todo deleted = findById(id);int deletedRecordCount = jooq.delete(TODOS).where(TODOS.ID.equal(id)).execute();return deleted;}
}

第4.3.5节。 jOOQ参考手册的DELETE语句提供了有关从数据库中删除数据的其他信息。

让我们继续前进,找出如何更新现有待办事项的信息。

更新现有的Todo条目

TodoRepository接口的公共Todo update(Todo todoEntry)方法将更新现有todo条目的信息。 我们可以通过执行以下步骤来实现此方法:

  1. update()方法添加到存储库类中,并使用@Transactional注释对方法进行注释。 这样可以确保UPDATE语句在读写事务中执行。
  2. 通过调用DateTimeService接口的getCurrentTimestamp()方法获取当前日期和时间。
  3. 通过执行以下步骤来更新待办事项的信息:
    1. 通过调用DSLContext接口的update(Table table)方法来创建新的UPDATE语句,并指定您要更新从todos表中找到的信息。
    2. 通过调用UpdateSetStep接口的set(Field field,T value)方法来设置新的描述,修改时间和标题。
    3. 通过调用UpdateWhereStep接口的where(Collection condition)方法来指定UPDATE语句的WHERE子句。 确保UPDATE语句更新待办事项条目,该待办事项条目是从作为方法参数给出的Todo对象中找到的。
    4. 通过调用Query接口的execute()方法执行UPDATE语句。
  4. 通过调用findById()方法获取更新的待办事项条目的信息。 将更新的待办事项条目的ID作为方法参数传递。
  5. 返回更新的待办事项条目的信息。

JOOQTodoRepository类的相关部分如下所示:

import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;import java.sql.Timestamp;import static net.petrikainulainen.spring.jooq.todo.db.tables.Todos.TODOS;@Repository
public class JOOQTodoRepository implements TodoRepository {private final DateTimeService dateTimeService;private final DSLContext jooq;//The constructor is omitted for the sake of clarity.@Transactional@Overridepublic Todo update(Todo todoEntry) {Timestamp currentTime = dateTimeService.getCurrentTimestamp();int updatedRecordCount = jooq.update(TODOS).set(TODOS.DESCRIPTION, todoEntry.getDescription()).set(TODOS.MODIFICATION_TIME, currentTime).set(TODOS.TITLE, todoEntry.getTitle()).where(TODOS.ID.equal(todoEntry.getId())).execute();return findById(todoEntry.getId());}
}
  • 第4.3.4节。 jOOQ参考手册的UPDATE语句提供了有关更新存储在数据库中的信息的其他信息。
  • 如果您使用的是Firebird或PostgreSQL数据库,则可以在update语句中使用RETURNING子句 (并避免使用多余的select子句)。

就这些了。 让我们总结一下我们从此博客文章中学到的知识。

摘要

现在,我们已经为待办事项实现了CRUD操作。 本教程教会了我们三件事:

  • 我们了解了如何以不妨碍我们为示例应用程序编写自动测试的方式获取当前日期和时间。
  • 我们了解了如何确保jOOQ执行的所有数据库查询都在事务内执行。
  • 我们学习了如何使用jOOQ API创建INSERTSELECTDELETEUPDATE语句。

本教程的下一部分描述了如何向示例应用程序添加支持排序和分页的搜索功能。

  • Github上提供了此博客文章的示例应用程序(尚未实现前端)。

翻译自: https://www.javacodegeeks.com/2014/04/using-jooq-with-spring-crud.html

在Spring中使用jOOQ:CRUD相关推荐

  1. java中jooq,在Spring中使用jOOQ源码案例

    Spring专题 在Spring中使用jOOQ源码案例 虽然ORM大部分性能问题是由开发者自己引起的,以只读方式使用ORM是不值得的,现在有一种其他可选方式,使用JOOQ,jOOQ从您的数据库生成Ja ...

  2. jooq中record_在Spring中使用jOOQ:CRUD

    jooq中record jOOQ是一个库,可帮助我们重新控制SQL. 它可以从我们的数据库生成代码,并允许我们使用其流畅的API来构建类型安全的数据库查询. 本教程前面的部分向我们介绍了如何配置示例应 ...

  3. Spring中的@ Component,@ Repository和@Service批注有什么区别?

    @Repository @Component , @Repository和@Service批注可以在Spring中互换使用吗,或者除了充当注解设备外,它们还提供任何特定功能吗? 换句话说,如果我有一个 ...

  4. spring中的JdbcTemplate——JdbcTemplate的最基本用法

    spring中的JdbcTemplate JdbcTemplate的作用: 它就是用于和数据库交互的,实现对表的CRUD操作 JdbcTemplate 概述 它是 spring 框架中提供的一个对象, ...

  5. Spring JDBC和JdbcTemplate CRUD与DataSource示例

    Spring JDBC示例和JdbcTemplate CRUD与DataSource示例 Spring JDBC是本教程的主题.数据库是大多数企业应用程序不可或缺的一部分.因此,当谈到Java EE框 ...

  6. JDBC在spring中的使用

    1.spring中的JDBCtmplate JDBCtmplate的作用: 它就是用于和数据库交互,实现对表的CRUD操作 如何创建该对象 对象中常用的方法 2.spring基于aop的事务控制 3. ...

  7. Spring Boot和jOOQ整合

    JOOQ简介 jOOQ,是一个ORM框架,利用其生成的Java代码和流畅的API,可以快速构建有类型约束的安全的SQL语句 jOOQ使我们的重心可以放在业务逻辑上,而Java与SQL的基础交互部分,都 ...

  8. Spring中Bean对象的存储和获取

    目录 1. 更简单的将bean存储到spring中 1.0 前置工作,在配置文件中设置bean扫描的根路径 1.1 通过注解将bean存储到spring中 1.1.1 @Controller[控制器] ...

  9. Hibernate+Spring+Struts2+ExtJS开发CRUD功能

    http://blog.csdn.net/myloon/archive/2007/11/08/1873652.aspx-----多谢这么好的文章 Hibernate+Spring+Struts2+Ex ...

最新文章

  1. vuejs出的手机app有哪些_详解Vue webapp项目通过HBulider打包原生APP
  2. 基于html5制作3D拳击游戏源码下载
  3. sublime使用笔记
  4. 分析BootstrapClassLoader/ExtClassLoader/AppClassLoader的加载路径 及父委托机制
  5. 设置Netbeans 6.5为英文界面
  6. java中枚举类型详解
  7. mysql基础测试_MySQL基础知识测试
  8. Visual Studio 2012 简体中文 旗舰正式版 ISO 下载
  9. const定义常量_go语言基本语法——常量constant
  10. C#中结构体排序方法(Array.sort() + ICompare)
  11. 【JVM原理探索,Java组件化架构实践
  12. 一张图彻底了解Unity脚本的生命周期
  13. 姚爱红计算机组成原理知识要点,计算机组成原理课程混合教学模式探究
  14. 【Windows Server 2019】企业虚拟专用网络服务的配置和管理(上)
  15. BP神经网络:误差反向传播公式的简单推导
  16. 什么是Anti-DDoS流量清洗?
  17. JBOSS4.0.2 HTTP集群配置详解
  18. 【Jmeter】分布式测试--单机均衡负载压测
  19. ISO 639-1语言列表
  20. OCR识别之LEADTOOLS介绍

热门文章

  1. linux netfilter 过滤数据包,Netfilter-iptabes报文过滤框架(一)
  2. php环境搭建sqlserver,ThinkPHP5.0/5.1对接SQLServer数据库(宝塔环境)
  3. Linux获取本机hostname函数,Linux下获得主机与域名-gethostbyname和gethostbyaddr
  4. browserquest php安装,请问一下browserquest-php项目换成GatewayWorker的形式需要怎么部署worker...
  5. sql server累计求和函数_SQL基础--SQL高级功能
  6. 如何写一个高效进程/线程池_关于高效企业测试的思考(1/6)
  7. aws lambda_API网关和AWS Lambda进行身份验证
  8. java+解析未知json_在Java中解析JSON时如何忽略未知属性– Jackson @JsonIgnoreProperties注释示例...
  9. facelets_不要在facelets中重复表情
  10. 使用Caffeine和Spring Boot的多个缓存配置