Часто замечаю за собой, что иногда даже какие то элементарные технические моменты, не всегда удается четко выразить. Для этого и решил попробовать пописать статьи на небольшие темы. Тема данной статьи в заголовке.
Я занимаюсь разработкой веб приложений. В текущем проекте есть пользователи, каждый имеет свою роль или несколько совмещенных. В двух словах о том, как организовано хранение ролей. Для этого используются битовые маски.
У пользователя есть поле rolesbit типа int, в котором хранится его роль. Каждой роли соответствует какая то маска. У админа это 1, у оператора 1 со сдвигом на одну позицию влево (0b1 << 1), у менеджера 1 со сдвигом на две позиции (0b1 << 2) и тд.
Таким образом, если у пользователя rolesbit == 0b111, то он имеет роль админа (0b001), роль оператора (0b010) и роль менеджера (0b100).
Для проверки наличия роли у пользователя, нужно использовать маску соответствующей роли и операцию побитового логического «И».
Например, пусть у одного пользователя rolesbit = 0b111, тогда
У другого пользователя rolesbit = 0b100, тогда
Появилась задача дополнить фильтр по пользователям фильтрацией по ролям. Фильтрация происходила путем извлечения объектов из базы удовлетворяющим параметрам фильтра. И тут возникла проблема, мы использовали Hibernate, но он не поддерживает операцию побитового «и» (нет в синтаксисе hql символа "&"). Конечно, можно написать sql запрос:
Без проблем получим всех «операторов».
Но, сейчас нужно было добавить один параметр поиска в уже существующий запрос, и очень не хотелось переписывать уже имеющуюся часть кода. Оказывается, отсутствие "&" в hql не так уж смертельно.
Нужно лишь вспоминить Перевод из 2 в 10 систему счисления:
Решается благодаря следующим правилам:
1. Деление на 2^х сместит биты на х позиций влево (напр 111/10 = 11)
2. Число по модулю 2 дает 1 если крайний бит установлен (в примере выше установлен)
Таким образом, общее истинное выражение
Соответственно, запрос будет выглядеть таким образом:
Я занимаюсь разработкой веб приложений. В текущем проекте есть пользователи, каждый имеет свою роль или несколько совмещенных. В двух словах о том, как организовано хранение ролей. Для этого используются битовые маски.
У пользователя есть поле rolesbit типа int, в котором хранится его роль. Каждой роли соответствует какая то маска. У админа это 1, у оператора 1 со сдвигом на одну позицию влево (0b1 << 1), у менеджера 1 со сдвигом на две позиции (0b1 << 2) и тд.
Таким образом, если у пользователя rolesbit == 0b111, то он имеет роль админа (0b001), роль оператора (0b010) и роль менеджера (0b100).
Для проверки наличия роли у пользователя, нужно использовать маску соответствующей роли и операцию побитового логического «И».
Например, пусть у одного пользователя rolesbit = 0b111, тогда
111 & 010 = 010, у пользователя есть роль оператора.У другого пользователя rolesbit = 0b100, тогда
100 & 010 = 000, у пользователя нет роли оператора. То есть маска показывает в каком разряде должна стоять единичка, результат умножения роли пользователя на маску показывает какое значение содержится в этом разряде, если 1 то пользователь имеет эту роль, если 0, то нет.Появилась задача дополнить фильтр по пользователям фильтрацией по ролям. Фильтрация происходила путем извлечения объектов из базы удовлетворяющим параметрам фильтра. И тут возникла проблема, мы использовали Hibernate, но он не поддерживает операцию побитового «и» (нет в синтаксисе hql символа "&"). Конечно, можно написать sql запрос:
session.createSQLQuery("select * from user where rolesbits & 2 !=0").list()Без проблем получим всех «операторов».
Но, сейчас нужно было добавить один параметр поиска в уже существующий запрос, и очень не хотелось переписывать уже имеющуюся часть кода. Оказывается, отсутствие "&" в hql не так уж смертельно.
Нужно лишь вспоминить Перевод из 2 в 10 систему счисления:
Решается благодаря следующим правилам:
1. Деление на 2^х сместит биты на х позиций влево (напр 111/10 = 11)
2. Число по модулю 2 дает 1 если крайний бит установлен (в примере выше установлен)
Таким образом, общее истинное выражение
(rolesbit / bitsMask) % 2 = 1 будет показывать что у пользователя с ролью rolesbit есть роль с маской bitsMask.Соответственно, запрос будет выглядеть таким образом:
session.createQuery("select u from user u where MOD(u.rolesbits/:bitsMask , 2) = 1").setParameter("bitsMask", role).list();