orderBy(Entity::getRank)
getOne
@Test
public void getOne() {
TUser tUser = userMapper.query()
.gt(TUser::getId, 1)
.getOne()
// Если найдено несколько записей, выбрасывается указанное исключение
.getIfThrow(new RuntimeException("Ошибка выполнения запроса"));
System.out.println(tUser);
}
@Test
public void getOne2() {
TUser tUser = userMapper.query()
.gt(TUser::getId, 1)
// Добавление ограничения limit 1
.getOne(true)
.get();
System.out.println(tUser);
}
@Test
public void getOne3() {
TUser tUser = userMapper.query()
.gt(TUser::getId, 1)
.getOne()
// Если найдено более одной записи, выбрасывается TooManyResultsException
.getOrThrow();
System.out.println(tUser);
}
@Test
public void getOne4() {
OneResult<TUser> result = userMapper.query()
.eq(TUser::getId, 3)
.getOne();
if (result.isError()) {
throw new RuntimeException("");
}
Optional<TUser> optional = result.getOptional();
if (optional.isPresent()) {
System.out.println(optional.get());
}
}
mybatis.ignore-query-when-missing-condition=true
# Когда значение true, отсутствие аннотации @Condition не приведёт к генерации условий запросаgetCount()
Обновлен метод update()
в LambdaQuery для недопущения полной замены таблицы
В LambdaService добавлен метод deleteByColumn()
## 3.0.10
Изменено имя метода пагинации в LambdaQuery для избежания конфликта с Query.page()
getById
listUniqueValue()
listValue()
, listUniqueValue()
, group()
, map()
getOptional()
и getValueOptional()
ignoreLogicDelete()
ignoreLogicDelete()
listAll()
toLambdaQuery()
в IParamget()
, getOptional()
, delete()
в LambdaQueryforceDeleteByColumn(column, value)
в DeleteMappercreateQuery()
, createUpdateQuery()
в LambdaService// Поиск по условиям
// SELECT ... FROM t_user WHERE username = ? AND age > 30
List<TUser> list = Query.query(TUser.class)
.eq(TUser::getUsername, "张三")
.gt(TUser::getAge, 30)
.list();
// Пагинация
// SELECT ... FROM t_user WHERE username = ? ORDER BY id DESC LIMIT 0, 10
PageInfo<TUser> pageInfo = Query.query(TUser.class)
.eq(TUser::getUsername, "张三")
.page(1, 10)
.orderByDesc(TUser::getId)
.page();
long total = pageInfo.getTotal();
List<TUser> records = pageInfo.getRecords();
``````md
## Логическое удаление по условию
## Принудительное удаление по условию
## Обновление данных
### Версия 2.12.2
- Поддержка пользовательских SQL-запросов при обновлении
```java
LambdaQuery<TUser> updateQuery2 = Query.lambdaUpdate(TUser.class);
updateQuery2.set(TUser::getUsername, "Пять")
.set(TUser::getRemark, "aaa")
.setExpression("add_time=now()")
.eq(TUser::getId, 6);
mapper.update(updateQuery2);
orderByAsc
и orderByDesc
в LambdaQueryВнимание: с версии 2.12.0 groupId был изменён на io.gitee.durcframework
<dependency>
<groupId>io.gitee.durcframework</groupId>
<artifactId>fastmybatis-spring-boot-starter</artifactId>
<version>3.0.17</version>
</dependency>
LambdaQuery<TUser> updateQuery = Query.lambdaUpdate(TUser.class);
updateQuery.set(TUser::getUsername, "Пять");
updateQuery.eq(TUser::getId, 6);
mapper.update(updateQuery2);
// Соответствующий SQL: UPDATE `t_user` SET username = ? WHERE id = ?
TUser obj = mapper.getByColumn(TUser::getId, 3);
Assert.assertNotNull(obj);
List<TUser> tUsers = mapper.listByColumn(TUser::getId, 1);
Assert.assertFalse(tUsers.isEmpty());
Assert.assertFalse(tUsers1.isEmpty());
List<TUser> tUsers2 = mapper.listByValues("id", 1, 2, 3);
Assert.assertFalse(tUsers2.isEmpty());
List<TUser> tUsers3 = mapper.listByCollection(TUser::getId, Arrays.asList(1, 2, 3));
Assert.assertFalse(tUsers3.isEmpty());
ColumnValue<TUser> columnValue = ColumnValue.create(TUser.class)
.set(TUser::getRemark, "123");
int i = mapper.updateByColumn(columnValue, TUser::getId, 1);
Assert.assertEquals(1, i);
int i2 = mapper.updateById(columnValue, 1);
Assert.assertEquals(1, i2);
---
## Версия 2.11.0
- Возможность указывать возвращаемые поля с помощью функционального интерфейса
```java
Query query = new Query().eq("id", 6);
// SELECT id, username FROM ...
TUser tUser = mapper.getBySpecifiedColumns(Columns.of(TUser::getId, TUser::getUsername), query);
List<TUser> list = mapper.listBySpecifiedColumns(Columns.of(TUser::getId, TUser::getUsername), query);
fastmybatis предоставляет четыре типа маскирования данных: номер телефона, номер паспорта, банковская карта, электронная почта. Пример маскирования номера телефона:
Добавьте аннотацию @Column
к полю класса и установите атрибут formatClass
.
@Table(name = "t_user", pk = @Pk(name = "id", strategy = PkStrategy.INCREMENT))
public class TUser {
...
// Маскирование номера телефона
@Column(formatClass = MobileSensitiveFormatter.class)
private String mobile;
...
}
Исправлено отсутствие игнора логического удаления при использовании методов listBySpecifiedColumns/listMap## Версия 2.9.8
Добавлен метод TenantContext.setDefaultBuilder для указания значения по умолчанию для tenantId
Обновлен Solon до версии 2.6.0
saveBatch(Collection<E> records, int partitionSize)
и saveBatchIgnoreNull(Collection<E> records, int partitionSize)
@Column(logicDelete = true, notDeleteValue = "{IS NULL}", deleteValue = "#datetime")
private Date deleteAt;
{<SQL>}
: указывает заполнение пользовательским SQL#datetime
: системная встроенная переменная, возвращает текущее время, поддерживает два значения: #datetime (дата и время), #date (только дата, например: 2023-08-10)Когда поле deleteAt
равно NULL, это означает, что данные не были удалены.
SELECT .. FROM table WHERE delete_at IS NULL;
При удалении используется текущее время для заполнения.
mapper.delete(obj)
UPDATE table SET delete_at = '2023-08-14 19:57:14' WHERE id = 1
Устранена проблема невозможности принудительного удаления через deleteByQuery## 2.9.0
Добавлены методы forceUpdateById(entity)
и forceUpdateById(entity, boolean)
, позволяющие обновлять null значения
Метод updateByQuery()
позволяет обновлять null значения
Оптимизация BaseService
Обновление null значений
TUser user = Entitys.of(TUser.class, 6);
user.setUsername("Ли Си");
user.setRemark(null);
// UPDATE `t_user` SET `username`='Ли Си', `remark`=null WHERE id = 6;
int i = userMapper.forceUpdateById(user);
print("updateByQuery --> " + i);
Assert.assertEquals(1, i);
// Базовое обновление нескольких записей по условию, может обновлять null значения
TUser user = Entitys.of(TUser.class);
user.setUsername("Ли Си");
user.setRemark(null);
Query query = Query.create().eq("username", "Чжан Сань");
/*
UPDATE
`t_user`
SET
`username`='Ли Си', `remark`=null
WHERE
username = 'Чжан Сань';
*/
int i = userMapper.updateByQuery(user, query);
С версии 2.8.1 доступна возможность использования JPA Query Method для поиска, достаточно определить метод в интерфейсе, без необходимости писать SQL-запросы.
Принцип работы: автоматическая генерация SQL-запроса на основе ключевых слов в названии метода.
На данный момент реализовано большинство функций, за исключением поддержки DISTINCT, все остальные поддерживаются. В Mapper можно определить метод, название которого начинается с findBy
.
/**
* ... where x.lastname = ?1 and x.firstname = ?2
* @param lastname
* @param firstname
* @return
*/
List<Student> findByLastnameAndFirstname(String lastname, String firstname);
После определения этого метода в Mapper его можно использовать непосредственно, без необходимости создания XML.```java @Test public void findByLastnameAndFirstname() { List students = mapper.findByLastnameAndFirstname("Чжан", "Сан"); Assert.assertEquals(1, students.size()); students.forEach(System.out::println); }
<table class="tableblock frame-all grid-all fit-content">
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><code>И</code></td>
<td class="tableblock halign-left valign-top"><code>findByLastnameAndFirstname</code></td>
<td class="tableblock halign-left valign-top"><code>… where x.lastname = ?1 and x.firstname = ?2</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Или</code></td>
<td class="tableblock halign-left valign-top"><code>findByLastnameOrFirstname</code></td>
<td class="tableblock halign-left valign-top"><code>… where x.lastname = ?1 or x.firstname = ?2</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Равно</code>, <code>Equals</code></td>
<td class="tableblock halign-left valign-top"><code>findByFirstname</code>,<code>findByFirstnameIs</code>,<code>findByFirstnameEquals</code></td>
<td class="tableblock halign-left valign-top"><code>… where x.firstname = ?1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Между</code></td>
<td class="tableblock halign-left valign-top"><code>findByStartDateBetween</code></td>
<td class="tableblock halign-left valign-top"><code>… where x.startDate between ?1 and ?2</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Меньше чем</code></td>
<td class="tableblock halign-left valign-top"><code>findByAgeLessThan</code></td>
<td class="tableblock halign-left valign-top"><code>… where x.age < ?1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Не больше чем</code></td>
<td class="tableblock halign-left valign-top"><code>findByAgeLessThanEqual</code></td>
<td class="tableblock halign-left valign-top"><code>… where x.age <= ?1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Больше чем</code></td>
<td class="tableblock halign-left valign-top"><code>findByAgeGreaterThan</code></td>
<td class="tableblock halign-left valign-top"><code>… where x.age > ?1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Не меньше чем</code></td>
<td class="tableblock halign-left valign-top"><code>findByAgeGreaterThanEqual</code></td>
<td class="tableblock halign-left valign-top"><code>… where x.age >= ?1</code></td>
</tr>
</tbody>
</table><table>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><code>age >= ? 1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>После</code></td>
</tr>
</tbody>
</table>
```markdown
<tr>
<td class="tableblock halign-left valign-top"><code>FindByStartDateAfter</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.startDate > ? 1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>ПреждеЧем</code></td>
<td class="tableblock halign-left valign-top"><code>FindByStartDateBefore</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.startDate < ? 1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>IsEmpty</code>, <code>Empty</code></td>
<td class="tableblock halign-left valign-top"><code>FindByAgeAndEmpty</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.age is null</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>IsNotEmpty</code>, <code>NotEmpty</code></td>
<td class="tableblock halign-left valign-top"><code>FindByAgeAndNotEmpty</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.age not null</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Схожесть</code></td>
<td class="tableblock halign-left valign-top"><code>FindByFirstNameSimilarity</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.firstname like '%? 1%'</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>НеCхожесть</code></td>
<td class="tableblock halign-left valign-top"><code>FindByFirstNameNotSimilarity</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.firstname not like '%? 1%'</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>НачинаетсяС</code></td>
<td class="tableblock halign-left valign-top"><code>FindByFirstNameStartsWith</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.firstname like '? 1%'</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>ЗаканчиваетсяНа</code></td>
<td class="tableblock halign-left valign-top"><code>FindByFirstNameEndsWith</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.firstname like '%? 1'</code></td>
</tr>
</tbody>
</table>```markdown
<table>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><code>… where x.firstname like '? 1'</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Contains</code></td>
<td class="tableblock halign-left valign-top"><code>FindByNameContains</code></td>
<td class="tableblock halign-left valign-top"><code>… where x.firstname like '? 1%'</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>SortBy</code></td>
<td class="tableblock halign-left valign-top"><code>findByAgeOrderByLastnameDesc</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.age = ? 1 order by x.lastname desc</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>Not</code></td>
<td class="tableblock halign-left valign-top"><code>findByLastnameNot</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.lastname <> ? 1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>In</code></td>
<td class="tableblock halign-left valign-top"><code>findByAgeIn(Collection<Age> ages)</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.age in ? 1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>NotIn</code></td>
<td class="tableblock halign-left valign-top"><code>findByAgeNotIn(Collection<Age> ages)</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.age not in ? 1</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>True</code></td>
<td class="tableblock halign-left valign-top"><code>findByActiveTrue()</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.active = true</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>False</code></td>
<td class="tableblock halign-left valign-top"><code>findByActiveFalse()</code></td>
<td class="tableblock halign-left valign-top"><code>... where x.active = false</code></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><code>IgnoreCase</code></td>
<td class="tableblock halign-left valign-top"><code>findByFirstnameIgnoreCase</code></td>
<td class="tableblock halign-left valign-top"><code>... where UPPER(x.firstname) = UPPER(? 1)</code></td>
</tr>
</tbody>
</table>
```</table>**Предостережения при использовании JPA запросов**:- В настоящее время реализовано большинство функций, см.: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods за исключением Distinct, который не поддерживается; остальные все поддерживаются.
- Названия методов должны начинаться с findBy.
- Имена полей базы данных должны следовать шаблону с нижним подчеркиванием, например: name, add_time; нотация camelCase не поддерживает JPA запросы.
- Если возникает ошибка `Parameter 'arg0' not found` при выполнении JPA запроса в IDE IntelliJ IDEA вместе с MyBatis, обратитесь к этой статье: https://www.cnblogs.com/JangoJing/p/10791831.html.
## Версия 2.7.0
- Упрощена стандартная форма использования, подробнее см. `fastmybatis-demo/fastmybatis-demo-standard`.
- Добавлен шаблон для базы данных H2.
- Добавлена возможность LambdaQuery.
```java
Query query = Query.query(TUser.class)
.eq(TUser::getId, 1)
.ge(TUser::getId, 1)
.in(TUser::getId, Arrays.asList(1, 2))
.between(TUser::getId, 1, 2)
.sql("id=1");
List<TUser> list = mapper.list(query);
Подвыражения
Query query = Query.query(TUser.class)
.eq(TUser::getId, 6)
// Подвыражение
.and(q -> q.eq(TUser::getUsername, "jim").orEq(TUser::getState, 1))
.orLambda(q -> q.eq(TUser::getId, 1).orBetween(TUser::getId, 1, 90))
.orEq(TUser::getUsername, "tom");
List<TUser> list = mapper.list(query);
* Удаление по нескольким первичным ключам id, когда есть поле логического удаления, выполняется UPDATE операция
*/
@Test
public void deleteByIds3() {
// Второй способ, через ThreadLocal
FastmybatisContext.setDeleteSetBlock(Arrays.asList(
new EqualColumn("username", "deleteUser"),
new EqualColumn("add_time", new Date())
));
int i = mapper.deleteByIds(Arrays.asList(1, 2, 3));
System.out.println("Удалено --> " + i);
}
t_user
t
WHERE
username = '王五' AND id <> 1 AND t.isdel = 0 LIMIT 0,1;
*/
int id = 1;
boolean checkExist = mapper.checkExist("username", "王五", id);
System.out.println(checkExist);
}
- Устранение проблемы физического удаления в базах данных, отличных от MySQL
## 2.6.1
- Оптимизация плагина вывода SQL
- Поддержка фреймворка Solon
## 2.6.0
Благодарим [@youbeiwuhuan](https://github.com/youbeiwuhuan) за предоставленный pull request
- В `@Column` аннотация добавлено новое перечисление logicDeleteStrategy [PR](https://github.com/durcframework/fastmybatis/pulls/10), варианты:
- LogicDeleteStrategy.FIXED_VALUE: стратегия с фиксированным значением, notDeleteValue и deleteValue применяются (`UPDATE t_user SET isdel = 1 WHERE id = 1 AND isdel = 0;`)
- LogicDeleteStrategy.ID_FILL: при удалении заполняется поле логического удаления значением основного ключа (`UPDATE t_user SET isdel = id WHERE id = 1 AND isdel = 0;`)- Добавлена конфигурация, которая запрещает использование SQL в интерфейсе Mapper [PR](https://gitee.com/durcframework/fastmybatis/pulls/9)
Установите `mybatis.disable-sql-annotation=true` в application.properties (по умолчанию false).
В интерфейсе Mapper нельзя использовать такие аннотации как `@Select`, `@Update`, `@Delete`, `@Insert`.
```java
// Кастомный SQL
@Update("update t_user set username = #{username} where id = #{id}")
int updateById(@Param("id") int id, @Param("username") String username);
При старте проекта будет выведено сообщение об ошибке.
Эта функция позволяет команде следовать единому стандарту кодирования, а кастомный SQL должен быть обязательно записан в XML.
<plugins>
<plugin interceptor="com.gitee.fastmybatis.core.support.plugin.SqlFormatterPlugin" />
</plugins>
saveBatchIgnoreNull
теперь игнорирует проверку размера списка, вместо этого сразу возвращает 0.Если вызывающий код не проверяет длину списка, то попытка сохранить пустой список может привести к ошибке. Это может повлиять на последующую бизнес-логику.
Поэтому если при массовом сохранении все элементы отсутствуют, будет выполнен тихий режим обработки с возвратом значения 0.
<R> PageEasyui<R> pageEasyui(Query query, Function<E, R> converter)
, который лучше всего работает вместе с компонентом easyui datagridsaveBatchBySpecifiedColumns
, позволяющего указывать конкретные поля для сохранения; это могут быть как свойства объекта, так и поля базы данныхupdateByQuery
, позволяющего указывать поля для игнора при обновлении; это могут быть как свойства объекта, так и поля базы данныхsaveBatchIgnoreNull
, который позволяет выполнять массовое сохранение, игнорируя поля со значением nullsun.net.www.protocol.file.FileURLConnection
при использовании JDK версии выше 8name.equals()
внутри метода findField
com.myapp.TreeDataTest
Существует таблица меню, которая имеет отношение "родитель-потомок"
CREATE TABLE `menu` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Основной ID',
`name` varchar(64) NOT NULL COMMENT 'Название меню',
`parent_id` int(11) NOT NULL DEFAULT '0' COMMENT 'ID родителя',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Таблица меню';
Класс-сущность:
public class Menu implements TreeNode<Menu, Integer> {
private Integer id;
private String name;
// ID родителя
private Integer parentId;
// Дочерние элементы
private List<Menu> children;
@Override
public Integer takeId() {
return getId();
}
@Override
public Integer takeParentId() {
return getParentId();
}
@Override
public void setChildren(List<Menu> children) {
this.children = children;
}
}
запрос
// Запрошенные данные уже имеют структуру родитель-потомок
List<Menu> дерево_данных = маппер.списокДерева(запрос, 0);
System.out.println(JSON.toJSONString(дерево_данных, SerializerFeature.PrettyFormat));
```вывод результата:
```json
[
{
"children": [
{
"children": [],
"id": 2,
"name": "яблоко",
"parentId": 1
},
{
"children": [],
"id": 3,
"name": "банан",
"parentId": 1
}
],
"id": 1,
"name": "фрукты",
"parentId": 0
}
]
listBySpecifiedColumns
listMap
saveBatch(Collection<E> records, int partitionSize)
, позволяющего выполнять групповое внесение данных с разделением на партииЗапрос listBySpecifiedColumns
с указанием псевдонимов:
List<String> columns = Arrays.asList(
"username as name",
"add_time as creationTime",
"add_time as additionTime",
"money"
);
// Выполнение запроса и преобразование в объекты класса User
List<User> users = mapper.listBySpecifiedColumns(columns, query, User.class);
public static class User {
private String name;
private String creationTime;
private Date additionTime;
private Float money;
// GET SET..
}
Групповое внесение данных с разделением на партии:
List<User> users = ... // 1000 элементов
// Групповое внесение данных, каждую партию состоит из 200 записей
mapper.saveBatch(users, 200);
listByCollection
, listByArray
, listByIds
когда значение пустое сразу возвращается пустой результатgetMap
в маппер, который позволяет преобразовать результат запроса в объект Map
saveBatch
для группового внесения данных, возвращает значения автоинкрементируемых первичных ключейУсловие OR:// WHERE id = ? OR username = ?
Query запрос = new Query()
.eq("id", 6)
.orEq("username", "jim");
Пример использования подусловий:
// WHERE (id = ? OR id BETWEEN ? AND ?) AND ( money > ? OR state = ? )
Query запрос = new Query()
.and(q -> q.eq("id", 3).orBetween("id", 4, 10))
.and(q -> q.gt("money", 1).orEq("state", 1));
// WHERE ( id = ? AND username = ? ) OR ( money > ? AND state = ? )
Query запрос = new Query()
.and(q -> q.eq("id", 3).eq("username", "jim"))
.or(q -> q.gt("money", 1).eq("state", 1));
Пример использования метода getMap
:
Query запрос = new Query()
.ge("id", 1);
// Запрос Map, где первичный ключ id является ключом, а строка данных — значением, что позволяет легко получить запись по её первичному ключу
// id -> TUser
Map<Integer, TUser> карта = маппер.getMap(запрос, TUser::getId);
System.out.println(карта.get(6));
Вставка в батче с возвратом автоинкрементного первичного ключа id:
List<TUser> users = ...;
mapper.saveBatch(users);
List<Integer> idList = users.stream()
.map(TUser::getId)
.collect(Collectors.toList());
System.out.println("Первичный ключ id: " + idList);
ignoreProperties
в метод updateByQuery
#pr
public class User {
private String username;
private Byte type = 1; // Здесь есть значение по умолчанию
}
User user = new User();
user.setUsername("Jim");
mapper.updateByQuery(user, new Query().eq("age", 10));
// Вышеуказанный метод генерирует SQL: UPDATE user SET username = 'Jim', type=1 WHERE age = 10
mapper.updateByQuery(user, new Query().eq("age", 10), "type"); // Не обновляем поле type
// Генерируемый выше SQL: UPDATE user SET username = 'Jim' WHERE age = 10
query.between("age", 1, 30);
com.myapp.TUserMapperTest#getColumnValue
)listMap
, pageMap
, saveMulti
, updateByQuery(Map<String, ?> setBlock, Query query)
fastmybatis-generator
, заменён на code-gen
BaseService
, заменён на IService
Обновление с 1.x до 2.0
Замените аннотации на уровне всего проекта:
javax.persistence.Table
замените на: com.gitee.fastmybatis.annotation.Table
javax.persistence.Column
замените на: com.gitee.fastmybatis.annotation.Column
Удалите аннотацию javax.persistence.Transient
, используйте ключевое слово transient
вместо этого. Удалите аннотацию javax.persistence.Id
, заменив её на @Table(name = "t_user", pk = @Pk(name = "id"))
.Удалите аннотацию javax.persistence.GeneratedValue
, заменив её на @Table(name = "t_user", pk = @Pk(name = "id", strategy = PkStrategy.INCREMENT))
.
int saveUnique(Collection<E> entities)
для массового сохранения и удаления дубликатов.int saveUnique(Collection<E> entities, Comparator<E> comparator)
для массового сохранения и удаления дубликатов с указанием компаратора.BaseService
.IService
.E getBySpecifiedColumns(List<String> columns, Query query)
— получение одной строки данных с указанием конкретных полей.<T> T getBySpecifiedColumns(List<String> columns, Query query, Class<T> clazz)
— получение одной строки данных с указанием конкретных полей и преобразование в указанный класс.List<E> listByIds(Collection<I> ids)
— получение данных по нескольким первичным ключам.T getColumnValue(String column, Query query, Class<T> clazz)
— получение значения одного поля.List<T> listColumnValues(String column, Query query, Class<T> clazz)
— получение значений указанной колонки.int saveOrUpdate(E entity)
— сохранение или обновление всех полей.int saveOrUpdateIgnoreNull(E entity)
— сохранение или обновление только тех полей, которые не равны null.int deleteByIds(Collection<I> ids)
— удаление по нескольким первичным ключам.int deleteByColumn(String column, Object value)
— удаление по значению указанного поля.Query
добавлена условная конструкция query.eq(StringUtils.hasText(name), "name", name);
.Устранены проблемы с возвратом булевых значений при использовании типа tinyint(1) в MySQL.
Проверка пустых строк теперь выполняется с использованием trim
. mybatis.empty-string-with-trim=true
.
Настройка игнорирования пустых строк теперь включена по умолчанию. mybatis.ignore-empty-string=true
.## 1.10.11
Устранены проблемы с копированием атрибутов в маппер.
mapper.pageBySpecifiedColumns
.mybatis.ignore-empty-string=true
.sql(String, Object...)
.SchMapper.listBySpecifiedColumns(List<java.lang.String>, Query, Class<T>)
, теперь Class поддерживает базовые типы.Пример использования:
// Получение списка значений столбца id
List<Integer> idList = mapper.listBySpecifiedColumns(Collections.singletonList("id"), query, Integer.class /* или int.class */);
for (Integer id : idList) {
System.out.println(id);
}
// Получение списка значений столбца id и преобразование в String
List<String> strIdList = mapper.listBySpecifiedColumns(Collections.singletonList("id"), query, String.class);
for (String id : strIdList) {
System.out.println("string:" + id);
}
// Получение списка значений столбца username
List<String> usernameList = mapper.listBySpecifiedColumns(Collections.singletonList("username"), query, String.class);
for (String username : usernameList) {
System.out.println(username);
}
``````markdown
## 1.10.2
- В Mapper добавлены следующие три метода:
- `listBySpecifiedColumns(List<String> columns, Query query, Class<T> clazz)`: Выполняет запрос для получения указанных колонок и преобразует результат в объект типа Class
- `listBySpecifiedColumns(List<String> columns, Query query)`: Выполняет запрос для получения указанных колонок и возвращает коллекцию объектов
- `PageInfo<E> page(Query query)`: Выполняет пагинацию запроса и возвращает информацию о странице
## 1.10.1
- Исправлена проблема отображения полей с нижним подчеркиванием
## Версия 1.10.0
- В Mapper добавлены четыре метода forceDelete, forceDeleteById, forceDeleteByQuery, forceById
- deleteByQuery теперь может проверять логическое поле удаления
## Версия 1.9.2
```- Устранена проблема с игнорированием логического поля удаления при связывании запросов
## Версия 1.9.1
- Удалён fastjson, заменён на gson
## Версия 1.9.0 (Java8)
- Поддержка LocalDateTime
## Версия 1.8.6
- Исправлена проблема с отключением заполнителей saveIgnoreNull
## Версия 1.8.5
- Исправлены проблемы с updateIgnoreNull и saveIgnoreNull
## Версия 1.8.4
- Исправлена проблема с горячей перезагрузкой пустого указателя
- Исправлена проблема с saveMulti в Oracle
## Версия 1.8.3
- Исправлена проблема с getByQuery случайного выбора одной записи в Oracle
## Версия 1.8.2
- Поддержка oracle sequence
## Версия 1.8.1
- Исправлена проблема с ignoreUpdateColumns
## Версия 1.8.0
- Глобальное указание на игнорирование полей для обновления
- Поддержка генерических ключей в сущностях
## Версия 1.7.4
- Исправление ошибок в Oracle
## Версия 1.7.3
- Оптимизация стратегий возврата id значений в сущности
## Версия 1.7.2
- Исправление ошибок условной операции удаления
## Версия 1.7.1
- Исправление ошибок аннотации Condition
## Версия 1.7.0
- Поддержка горячей перезагрузки, изменения xml без необходимости перезапуска
## Версия 1.6.0
- Аннотация @Condition добавляет атрибут handlerClass
- Аннотация @Condition добавляет атрибут ignoreValue
## Версия 1.5.1
- Аннотация @Condition добавляет атрибут index для оптимизации порядка условий
## Версия 1.5.0
- Аннотация @Condition добавляет атрибут index для изменения порядка условий
- Добавлена аннотация LazyFetch
- Исправление ошибок ввода данных в Oracle## Версия 1.4.2
- Исправление ошибок ленивой загрузки
## Версия 1.4.1
- Метод `mapper.updateByQuery()` теперь поддерживает логическое поле удаления
## Версия 1.4.0
- Добавлена функция ленивой загрузки один-к-одному в сущностях
- Исправление ошибок запросов
## Версия 1.3.0 (содержит ошибки, не использовать этот выпуск)
- Метод `updateByQuery` теперь может принудительно обновлять null значения
- Исправление ошибок использования `distinct`
- Аннотация `@Condition` теперь может применяться к полям
## Версия 1.2.0
- Исправление ошибок объединения пользовательских xml файлов
- Добавлен метод `updateByMap`
- Добавлен способ использования `distinct`
## Версия 1.1.1
- Исправление ошибок парсинга статических полей в сущностях
## Версия 1.1.0
- Предоставлено разделение страниц easyui таблиц, см MapperUtil.java
## Версия 1.0.17
- Исправление шаблонов для SQL Server (обязательно обновиться до этой версии при использовании SQL Server базы данных)
## Версия 1.0.16
- Аннотация `@Condition` добавляет атрибут `ignoreEmptyString`, https://durcframework.gitee.io/fastmybatis/#27040701
## Версия 1.0.15
- Оптимизация производительности (стандарт Alibaba + Sonar)
## Версия 1.0.14
- Оптимизация кода (Sonar)
## Версия 1.0.13
- Объединение PR2, https://gitee.com/durcframework/fastmybatis/pulls/2
## Версия 1.0.12
- Исправление шаблонов
## Версия 1.0.11
- Оптимизация свойства копирования
## Версия 1.0.10
- Улучшение Mapper.xml, разные Mapper файлы могут указывать один namespace, который будет объединён в конечном итоге
## Версия 1.0.9- Оптимизация методов преобразования объектов
## 1.0.8
- Исправление ошибки при передаче `pageSize` = 0
## 1.0.7
- Конструктор параметров может получать свойства родительского класса
## 1.0.6
- Добавлено игнорирование условий в `EasyuiDtagridParam`
## 1.0.5
- Поддержка параметров таблицы EasyUI
## 1.0.4
- Исправление ошибки отображения мапперов без сущностной модели
## 1.0.3
- Добавлена возможность принудительного выполнения запроса, см. `TUserMapperTest.testForceQuery()`
## 1.0.2
- Улучшение комментариев
- Оптимизация кода
## 1.0.1 Первый выпуск
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.