Цель BeetlSQL — предоставление эффективной разработки, эффективного обслуживания и эффективной работы в качестве фреймворка доступа к базам данных. В случае нескольких баз данных в одной системе обеспечивает единый способ написания кода. Поддерживается следующие платформы:
BeetlSQL это не просто простой аналог MyBatis или Hibernate, но также их сочетание. BeetlSQL имеет более высокую цель — сравняться или превзойти Spring Data, предлагая единую платформу для доступа к данным, будь то традиционные базы данных, большие данные, движки запросов или оперативные базы данных.> Прямое онлайн использование BeetlSQL http://121.42.237.11:8080/beetlsql_online/
@Fetch
, @FetchMany
и т.д. |
| sql-mapper | Расширяет определение мапперов, позволяет пользователям создавать свои собственные мапперы и аннотации для мапперов. |
| sql-integration | Интеграция с фреймворками Spring, Solon, JFinal и т.д., а также примеры. |
| sql-query | Query и LambdaQuery, использование Java API для создания и работы с SQL. |
| sql-mapping | Поддерживает отображение между одной таблицей, несколькими таблицами и POJO, поддерживает определение JSON, XML и методы отображения, или соглашения по умолчанию. |
| sql-template | Реализация шаблонов Beetl и поддержка других языков шаблонов. |
| sql-gen | Абстрактный пакет генерации кода, предоставляющий стандартные реализации для генерации DAO, SQL-файлов, md-документов. |
| sql-db-support | Поддержка тестирования и проверки различных баз данных, поддерживаются более чем 20 типов баз данных. |
| sql-samples | Включает сотни примеров использования BeetlSQL. |
| sql-test | Включает сотни примеров юнит-тестов. |Новое расширение BeetlSQL| Расширение BeetlSQL | Функционал |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| sql-xml | Высоко имитирующий XML синтаксис MyBatis, если вы предпочитаете использовать XML для написания шаблонов SQL, то это расширение для вас |
| sql-accelerator | Ускоряет производительность через оптимизацию отражения, кэширование, что позволяет BeetlSQL увеличить производительность на 50% - 200%, приближаясь к половине производительности рукописного JDBC |
| sql-firewall | Защита SQL, чтобы случайно написанные запросы не повредили базу данных |
| sql-dynamic-table | Поддерживает доступ к динамическим таблицам как к статичным, упрощая разработку бизнес-логики для динамического создания таблиц |
| sql-bean-encrypt | Поддерживает шифрование/дешифрование полей с использованием @MD5
, @AES
|
| sql-rewrite | Использует переопределение SQL, поддерживающее односущностный многопользовательский режим, логическое удаление, управление правами доступа |
| SAGA (экспериментальное) | BeetlSQL реализация SAGA, используемая для микросервисных транзакций |
Результаты оптимизации производительности с использованием ускоряющего расширения: достигается производительность, близкая к половине производительности рукописного JDBC.| Запрос | Тестовый контент | BeetlSQL (операции/мс) | Чистый JDBC | MyBatis | JPA | | --------------------------- | ---------------------------------- | ------------------------ | ----------- | -------- | --- | | beetlsqlExecuteJdbc | Прямое выполнение JDBC | 318 | 678 | / | 64 | | beetlsqlExecuteTemplate | Выполнение шаблона SQL | 268 | / | 44 | 66 | | beetlsqlFile | Сохранение SQL в файлах для управления | 266 | / | 41 | / | | beetlsqlInsert | Вставка одной записи | 129 | 248 | 43 | 59 | | beetlsqlGetAll | Получение всех данных | 13 | 40 | 4 | 5 | | beetlsqlLambdaQuery | Написание SQL запроса с помощью Java функций | 196 | / | 9 | / | | beetlsqlPageQuery | Постраничная выборка | 159 | / | 17 | 59 | | beetlsqlSelectById | Выборка одной записи | 259 | 670 | 43 | 61 |
Инструкция использования BeetlSQL 3.x, текущий выпуск
git clone https://gitee.com/xiandafu/beetlsql
mvn clean package
# Если вы хотите изменить исходный код
mvn clean install
Примечание: BeetlSQL 3 интегрирована с Spring и поддерживает большие объемы данных. Даже если вы настроили внутренние зеркала, возможно, вам придётся долго ждать загрузки зависимостей для работы с большими данными. Чтобы ускорить компиляцию, вам следует открыть pom.xml
, и отключить модули sql-integration
, sql-db-support
, sql-jmh
.
<modules>
<!-- Основные функции -->
<module>sql-core</module>
<module>sql-mapper</module>
<module>sql-util</module>
<module>sql-fetch</module>
<!-- Упаковка вместе -->
<module>beetlsql</module>
<module>sql-gen</module>
<module>sql-test</module>
<module>sql-samples</module>
<module>sql-xml</module>
<module>sql-saga</module>
<!-- Интеграция и расширение большого количества баз данных могут быть отключены для ускорения загрузки jar -->
<!-- <module>sql-integration</module>-->
<!-- <module>sql-jmh</module>-->
<!-- <module>sql-db-support</module>-->
</modules>
Вы можете найти все примеры в модуле sql-samples
, либо запустить тестовые примеры из модуля sql-test
. Также вы найдёте связанные примеры в различных модулях тестирования в sql-integration
. Все примеры основаны на базе данных H2, которая работает в памяти и может быть многократно запущена. Пример sql-samples
включает три модуля с примерами около OnClickListener:
quickstart: Основные примеры использования BeetlSQL, позволяющие быстро освоить BeetlSQL3.
usage: Все API и функции BeetlSQL.
plugin: Примеры продвинутых расширений BeetlSQL.На примере модуля usuage приведены следующие коды:
S01MapperSelectSample — 15 примеров демонстрации запросов в маппере.
S02MapperUpdateSample — 11 примеров обновления данных в маппере.
S03MapperPageSample — 3 примера пагинации запросов в маппере.
S04QuerySample — 9 примеров выполнения запросов через Query.
S05QueryUpdateSample — 3 примера выполнения операций update через Query.
S06SelectSample — 14 примеров выполнения запросов через SQLManager.
S07InsertSample — 8 примеров вставки новых данных через SQLManager, включая генерацию первичных ключей.
S08UpdateSample — 6 примеров обновления данных.
S09JsonMappingSample — 5 примеров конфигурации JSON-отображения.
S10FetchSample — 2 примера отображения связей.
S11BeetlFunctionSample — 2 примера использования пользовательских функций SQL.
BeetlSQL предлагает подход Saga для управления транзакциями, но это пока экспериментальная версия. Приглашаем смелых людей попробовать и вместе улучшить эту часть. Примеры можно найти в модуле Saga в юнит-тестах.
UserEntity user = sqlManager.unique(UserEntity.class, 1);
user.setName("ok123");
sqlManager.updateById(user);
UserEntity newUser = new UserEntity();
newUser.setName("newUser");
newUser.setDepartmentId(1);
sqlManager.insert(newUser);
```Дружественный вывод логов позволяет обратиться к месту вызова кода.
┏━━━━━ Debug [user.selectUserAndDepartment] ━━━ ┣ SQL: select * from user where 1 = 1 and id=? ┣ Параметры: [1] ┣ Положение: org.beetl.sql.test.QuickTest.main(QuickTest.java:47) ┣ Время: 23ms ┣ Результат: [1] ┗━━━━━ Debug [user.selectUserAndDepartment] ━━━
```java
String sql = "SELECT * FROM user WHERE id=?";
Integer id = 1;
SQLReady sqlReady = new SQLReady(sql, new Object[]{id});
List<UserEntity> userEntities = sqlManager.execute(sqlReady, UserEntity.class);
// Map также может использоваться как входной/выходной параметр
List<Map> listMap = sqlManager.execute(sqlReady, Map.class);
String sql = "SELECT * FROM user WHERE department_id=#{id} AND name=#{name}";
UserEntity paras = new UserEntity();
paras.setDepartmentId(1);
paras.setName("lijz");
List<UserEntity> list = sqlManager.execute(sql, UserEntity.class, paras);
Строковая переменная sql
= "выбрать * из user где id входит в (#{join(ids)})";
Список списков = Arrays.asList(1, 2, 3, 4, 5);
Карта параметров = новый HashMap();
параметры.put("ids", список);
Список пользователи = sqlManager.execute(sql, UserEntity.class, параметры);
Поддерживает рефакторинг
LambdaQuery<UserEntity> query = sqlManager.lambdaQuery(UserEntity.class);
Список<UserEntity> сущности = query.равенство(UserEntity::getDepartmentId, 1)
.неNull(UserEntity::getName).выбор();
// Доступ к user.md#select
SqlId id = SqlId.of("user", "select");
Карта параметров = новый HashMap<>();
параметры.put("name", "n");
Список<UserEntity> результат = sqlManager.select(id, UserEntity.class, параметры);
### Пример 6 Поддержка сложной отображаемой модели
Поддерживает сложную модель отображения, аналогично MyBatis
@Data
@ResultProvider(AutoJsonMapper.class)
public static class MyUserView {
Integer id;
String name;
DepartmentEntity dept;
}
{
"id": "id",
"name": "name",
"dept": {
"id": "dept_id",
"name": "dept_name"
},
"roles": {
"id": "r_id",
"name": "r_name"
}
}
@SqlResource("user") /*sql файл находится в user.md*/
public interface UserMapper extends BaseMapper<UserEntity> {
@Sql("выбрать * из user где id = ?")
UserEntity queryUserById(Integer id);
@Sql("обновить user установить name=? где id = ?")
@Update
int updateName(String name, Integer id);
@SqlTemplate("выбрать * из user где id = #{id}")
UserEntity getUserById(Integer id);
@SpringData/*стиль Spring Data*/
List<UserEntity> queryByNameOrderById(String name);
/**
* Можно определить интерфейс по умолчанию
* @return
*/
default List<DepartmentEntity> findAllDepartment() {
Map<String, Object> params = new HashMap<>();
params.put("excludeId", 1);
List<DepartmentEntity> list = getSQLManager().execute(
"выбрать * из department где id != #{excludeId}",
DepartmentEntity.class,
params
);
return list;
}
}
/**
* Вызов sql файла user.md#select, имя метода совпадает с названием фрагмента в markdown
* @param name
* @return
*/
List<UserEntity> select(String name);
/**
* Пагинация запроса, вызывает user.md#pageQuery
* @param deptId
* @param pageRequest
* @return
*/
PageResult<UserEntity> pageQuery(Integer deptId, PageRequest pageRequest);
@SqlProvider(provider = S01MapperSelectSample.SelectUserProvider.class)
List<UserEntity> queryUserByCondition(String name);
@SqlTemplateProvider(provider = S01MapperSelectSample.SelectUs)
List<UserEntity> queryUserByTemplateCondition(String name);
``` @Matcher /*Создание собственной аннотации Matcher также легко*/
List<UserEntity> query(Condition condition, String name);
}
Аннотации, используемые в Mapper, могут быть настроены и расширены самостоятельно
Позволяет после выполнения запроса снова получить связанные объекты. На самом деле, @FetchOne и @FetchMany являются пользовательскими аннотациями, которые можно расширять.
@Data
@Table(name="user")
@Fetch
public static class UserData {
@Auto
private Integer id;
private String name;
private Integer departmentId;
@FetchOne("departmentId")
private DepartmentData dept;
}
/**
* Данные департаментов используют "b" sqlmanager
*/
@Data
@Table(name="department")
@Fetch
public static class DepartmentData {
@Auto
private Integer id;
private String name;
@FetchMany("departmentId")
private List<UserData> users;
}
Можно расширить метод decide класса ConditionalSQLManager для выбора нужного SQLManager.
SQLManager a = SampleHelper.init();
SQLManager b = SampleHelper.init();
Map<String, SQLManager> map = new HashMap<>();
map.put("a", a);
map.put("b", b);
SQLManager sqlManager = new ConditionalSQLManager(a, map);
// Разные объекты используют различные sqlManager для операций и хранятся в разных базах данных
UserData user = new UserData();
user.setName("hello");
user.setDepartmentId(2);
sqlManager.insert(user);
DepartmentData dept = new DepartmentData();
dept.setName("dept");
sqlManager.insert(dept);
Используйте аннотацию @TargetSQLManager для выбора SQL Manager.```java @Data @Table(name = "department") @TargetSQLManager("b") public static class DepartmentData { @Auto private Integer id; private String name; }
### Пример 10 Если вы хотите добавить идентификатор sqlId каждому SQL запросу
Эта возможность позволяет упрощать взаимодействие между DBA базы данных и программистами.
```java
public static class SqlIdAppendInterceptor implements Interceptor {
@Override
public void before(InterceptorContext ctx) {
ExecuteContext context = ctx.getExecuteContext();
String jdbcSql = context.sqlResult.jdbcSql;
String info = context.sqlId.toString();
// Добавляем комментарий к SQL запросу, отправленному в базу данных, чтобы облегчить общение между DBA и разработчиками
jdbcSql = "/*" + info + "*/\n" + jdbcSql;
context.sqlResult.jdbcSql = jdbcSql;
}
}
Можно использовать встроенный кодогенерационный фреймворк для генерации кода и документов, а также создавать свои собственные, расширяя класс SourceBuilder.
List<SourceBuilder> sourceBuilder = new ArrayList<>();
SourceBuilder entityBuilder = new EntitySourceBuilder();
SourceBuilder mapperBuilder = new MapperSourceBuilder();
SourceBuilder mdBuilder = new MDSourceBuilder();
// Генерация документации в формате markdown
SourceBuilder docBuilder = new MDDocBuilder();
sourceBuilder.add(entityBuilder);
sourceBuilder.add(mapperBuilder);
sourceBuilder.add(mdBuilder);
sourceBuilder.add(docBuilder);
SourceConfig config = new SourceConfig(sqlManager, sourceBuilder);
// Вывод только в консоль
ConsoleOnlyProject project = new ConsoleOnlyProject();
String tableName = "USER";
config.gen(tableName, project);
GroupTemplate groupTemplate = groupTemplate();
groupTemplate.registerFunction("nextDay", new NextDayFunction());
```Map map = new HashMap<>();
map.put("date", new Date());
String sql = "SELECT * FROM user WHERE create_time IS NOT NULL AND create_time < #{nextDay(date)}";
List<UserEntity> count = sqlManager.execute(sql, UserEntity.class, map);
Функция nextDay является Beetl функцией, которая легко определяется и используется в шаблонах SQL.
```java
public static class NextDayFunction implements Function {
Разбиение таблиц по ID или контексту автоматически, toTable
— это определенная функция Beetl,
static final String USER_TABLE = "${toTable('user', id)}";
@Data
@Table(name = USER_TABLE)
public static class MyUser {
@AssignID
private Integer id;
private String name;
}
Определение аннотации Jackson, @Builder
является аннотацией для этой аннотации, что указывает использовать Builder для выполнения класса. Как видно, расширяемость аннотаций BeetlSQL происходит благодаря использованию @Builder
.
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD, ElementType.FIELD })
@Builder(JacksonConvert.class)
public @interface Jackson {
}
Определение аннотации @Tenant
для POJO, при выполнении BeetlSQL SQL получает дополнительные параметры. Здесь также используется @Builder
.
/**
* Комбинированная аннотация, которая добавляет дополнительную информацию о снимке арендатора, чтобы реализовать разделение таблиц или баз данных по арендатору
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.TYPE })
@Builder(TenantContext.class)
public @interface Tenant {
}
Использование XML вместо JSON в качестве маппинга
@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.TYPE })
@Builder(ProviderConfig.class)
public @interface XmlMapping {
String path() default "";
}
```Для более подробной информации о том, как определять свои собственные аннотации, обратитесь к примеру кода PluginAnnotationSample.
### Пример 15 Транзакции микросервисов
Кроме того, что BeetlSQL интегрирована со стандартными менеджерами транзакций, она также предоставляет поддержку Saga-транзакций, поддерживающую многобазовые транзакции и транзакции микросервисов. Её принцип заключается в автоматическом предоставлении обратных операций каждому действию, таким образом insert имеет обратную операцию deleteById, и эти действия передаются Saga-серверу для планирования задач. Это обеспечивает взаимодействие через Kafka между клиентским приложением (каждым APP) и сервером Saga, гарантируя надежную передачу задач и их последующее выполнение системой.
```java
String orderAddUrl = "http://127.0.0.1:8081/order/item/{orderId}/{userId}/{fee}";
String userBalanceUpdateUrl = "http://127.0.0.1:8082/user/fee/{orderId}/{userId}/{fee}";
..........
SagaContext sagaContext = SagaContext.sagaContextFactory.current();
try {
sagaContext.start(gid);
// Моделирование вызова двух микросервисов, заказа и пользователя
rest.postForEntity(orderAddUrl, null, String.class, paras);
rest.postForEntity(userBalanceUpdateUrl, null, String.class, paras);
if (1 == 1) {
throw new RuntimeException("Моделирование ошибки, проверьте saga-server для эффекта");
}
} catch (Exception e) {
log.info("Ошибка " + e.getMessage());
log.info("Начало отката " + e.getMessage());
sagaContext.rollback();
return e.getMessage();
}
Пример с системой пользователей (источник кода — DemoController), где userBalanceUpdateUrl
соответствует следующей логике списания средств:```java
@Autowired
UserMapper userMapper;
@Transactional(propagation= Propagation.NEVER)
public void update(String orderId, String userId, Integer fee) {
SagaContext sagaContext = SagaContext.sagaContextFactory.current();
try {
sagaContext.start(orderId);
UserEntity user = userMapper.unique(userId);
user.setBalance(user.getBalance() - fee);
userMapper.updateById(user);
sagaContext.commit();
} catch (Exception e) {
sagaContext.rollback();
}
}
Здесь `UserMapper` является подклассом `SagaMapper` (а не `BaseMapper`) и предоставляет обратные операции для каждого действия.
```java
public interface SagaMapper<T> {
/** Saga модифицированный интерфейс **/
@AutoMapper(SagaInsertAMI.class)
void insert(T entity);
@AutoMapper(SagaUpdateByIdAMI.class)
int updateById(T entity);
@AutoMapper(SagaDeleteByIdAMI.class)
int deleteById(Object key);
}
Кроме SQLManager
и ClassAnnotations
, любую часть можно расширять.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )