В этом посте мы создадим простой пользовательский crud. Данные будут сохранены в Redis. Для взаимодействия с Redis мы будем использовать библиотеку Jedis. CDI для Depedency Injection и Servlet 3.0 для представления.
Давайте начнем с части Redis / Jedis. Вы можете найти обзор Redis и Jedis в этих постах .
Давайте начнем с класса User, мы можем видеть это ниже:
01
02
03
04
05
06
07
08
09
10
11
12
|
public class User { private String firstName; private String lastName; private String email; private String gender; private long id; } |
Теперь давайте определим ключи, которые мы будем использовать для хранения пользовательской информации в Redis. В нашем примере мы будем использовать три ключа:
- user: ids — Это будет использоваться для генерации идентификаторов пользователя с помощью команды INCR.
- user: all — Redis List для хранения всех идентификаторов пользователей
- user: <id>: data — будет один ключ с этим шаблоном для каждого пользователя в системе. Эти ключи будут хешами;
Когда мы собираемся добавить нового пользователя в систему, мы будем обрабатывать три ключа, как мы видим на следующих шагах:
- Сначала мы получаем новый идентификатор пользователя, увеличивая значение user: ids key: INCR user: ids
- Затем мы добавляем его пользователю: весь список: lpush пользователь: все возвращенный идентификатор
- И добавьте информацию о пользователе в свой собственный хеш: HMSET user: <returnId>: значение поля данных.
Мы можем увидеть этот код в действии методом UserDAO.addUser:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public User addUser(User user){ long userId = jedis.incr(Keys.USER_IDS.key()); user.setId(userId); //Getting the Pipeline Pipeline pipeline = jedis.pipelined(); //add to users list pipeline.lpush(Keys.USER_ALL.key(), String.valueOf(userId)); //add to the hash pipeline.hmset(Keys.USER_DATA.formated(String.valueOf(userId)), BeanUtil.toMap(user)); pipeline.sync(); return user; } |
Объясняя приведенный выше код, сначала мы получаем новый идентификатор пользователя. Переменная jedis является атрибутом класса UserDAO, это экземпляр класса Jedis. Чтобы избежать трех сетевых обращений к серверу redis, мы используем концепцию Pipeline, поэтому при одном обращении к серверу redis мы добавим идентификатор пользователя в user: all list и информацию о пользователе в user: <id>: data хэш.
Команды, выполняемые экземпляром конвейера, будут выполняться на сервере redis после вызова pipe.sync () . Мы создали класс util для преобразования пользовательского объекта в Map <String, String> для хранения в хэше redis.
Чтобы увидеть детали пользователя, у нас есть метод в DAO для получения пользователя, который мы можем увидеть ниже:
1
2
3
4
5
6
|
public User getUser( long userId){ String userInfoKey = Keys.USER_DATA.formated(String.valueOf(userId)); Map<String, String> properties = jedis.hgetAll(userInfoKey); return BeanUtil.populate(properties, new User()); } |
Как мы видим, это простой метод, в основном мы вызываем команду HGETALL для извлечения всех полей из хэша. API-интерфейс Jedis возвращает его в виде карты, поэтому мы можем просто заполнить пользовательские свойства карты.
Для удаления пользователя мы создали метод ниже:
1
2
3
4
5
6
7
8
|
public boolean remove( long userId){ String userInfoKey = Keys.USER_DATA.formated(String.valueOf(userId)); Pipeline pipeline = jedis.pipelined(); Response<Long> responseDel = pipeline.del(userInfoKey); Response<Long> responseLrem = pipeline.lrem(Keys.USER_ALL.key(), 0 , String.valueOf(userId)); pipeline.sync(); return responseDel.get() > 0 && responseLrem.get() > 0 ; } |
В методе ниже мы также используем концепцию конвейерной обработки, когда нам нужно удалить ключ Hash и идентификатор пользователя из списка user: all. Команда LREM удаляет значение из списка, ноль указывает на удаление всех вхождений этого значения в списке. В этом методе мы также используем возвращаемые значения команд, используя объекты Response, возвращаемые каждой командой. Мы можем использовать эти объекты только после вызова метода синхронизации .
Метод обновления очень прост, мы можем увидеть его ниже:
1
2
3
4
5
|
public User update(User user){ String userInfoKey = Keys.USER_DATA.formated(String.valueOf(user.getId())); jedis.hmset(userInfoKey ,BeanUtil.toMap(user)); return user; } |
Это просто вызов HMSET, передающий карту со всеми атрибутами пользователя, которые должны быть обновлены в хэше redis.
Для составления списка пользователей нам также необходимо использовать конвейер. Redis не предоставляет команду HMGETALL, поэтому, чтобы получить всех пользователей с одним сетевым подключением, мы сделаем это по конвейеру.
Метод списка можно увидеть ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public List<User> list(){ List<User> users = new ArrayList<User>(); //Get all user ids from the redis list using LRANGE List<String> allUserIds = jedis.lrange(Keys.USER_ALL.key(), 0 , - 1 ); if (allUserIds != null && !allUserIds.isEmpty()){ List<Response<Map<String,String>>> responseList = new ArrayList<Response<Map<String,String>>>(); Pipeline pipeline = jedis.pipelined(); for (String userId : allUserIds){ //call HGETALL for each user id responseList.add(pipeline.hgetAll(Keys.USER_DATA.formated(userId))); } pipeline.sync(); //iterate over the pipelined results for (Response<Map<String, String>> properties : responseList){ users.add(BeanUtil.populate(properties.get(), new User())); } } return users; } |
В этом методе мы сначала получаем все идентификаторы пользователя из списка user: все с помощью команды LRANGE. После этого мы выполняем «HMGETALL» через конвейер, вызываем команду HGETALL для каждого пользователя, затем строим пользовательские объекты из возвращенных экземпляров Map.
В этом первом посте мы увидели, как взаимодействовать с сервером Redis с помощью API-интерфейса Jedis для хранения и получения информации о пользователе. Мы увидели концепцию и использование Pipeline . В следующем посте мы покажем, как использовать CDI для Dependency Injection и Servlet 3.0 для представления.