И (AND)
Метод | Описание |
---|---|
eqByType(Object) | Соединение строк с помощью оператора «=», в зависимости от типа аргумента. Например, eqByType(1) генерирует 1, а eqByType("1") генерирует '1'. |
ИЛИ (OR)
Метод | Описание |
---|---|
byType(Object) | Генерирует строку в соответствии с типом аргумента, например, byType(1) создаёт 1, byType("1") создаёт '1' |
4.3 Использование соединения для запросов и сортировки
Запрос на оценку ниже проходного балла:
sqlFactory.sql().SELECT("s.name","c.subject_name","c.score_value")
.FROM("score c")
.LEFT_JOIN_ON("student s", "s.id=c.student_id")
.WHERE("c.score_value<60")
.ORDER_BY("c.score_value")
.build();
/*
Генерируется SQL-запрос:
SELECT s.name, c.subject,c.score_value
FROM score c
LEFT OUTER JOIN student s ON (s.id = c.student_id)
WHERE c.score_value < 60
ORDER BY c.score_value
*/
4.4 Групповые запросы
Запрос общей оценки каждого студента:
sqlFactory.sql().SELECT("s.name", "sum(c.score_value) total_score")
.FROM("score c")
.LEFT_JOIN_ON("student s", "s.id=c.student_id")
.GROUP_BY("s.name")
.build()
/*
Генерируется SQL-запрос:
SELECT s.name, sum(c.score_value) total_score
FROM score c
LEFT OUTER JOIN student s ON (s.id = c.student_id)
GROUP BY s.name
*/
4.5 IN-оператор
Поскольку Jdbc не поддерживает привязку параметров IN, FastSQL предлагает несколько способов непосредственного объединения IN-оператора:
//1.Использование строки
sqlFactory.sql().SELECT("*")
.FROM("student")
.WHERE("name").IN("('小明','小红')")
.build();
//2.Использование коллекции (List,Set и т.д.)
sqlFactory.sql().SELECT("*")
.FROM("student")
.WHERE("name").IN(Lists.newArrayList("小明","小红"))
.build();
//3.Использование массива
sqlFactory.sql().SELECT("*")
.FROM("student")
.WHERE("name").IN(new Object[]{"小明","小红"})
.build();
//4.Использование переменного параметра (наиболее лаконично)
sqlFactory.sql().SELECT("*")
.FROM("student")
.WHERE("name").IN_var("小明","小红")
.build();
Генерируемый SQL-запрос: SELECT * FROM student WHERE name IN ('小明', '小红').
4.6 Использование метода $_$() для подзапросов
Запрос оценок выше среднего (можно использовать метод $_$())
sqlFactory.sql().SELECT("*")
.FROM("score")
.$_$(
sqlFactory.sql().SELECT("avg(score_value)").FROM("score")
)
.WHERE("score_value >")
.build();
//Генерируется SQL-запрос:
//SELECT * FROM score WHERE score_value > ( SELECT avg(score_value) FROM score )
Подзапросы с использованием IN
sqlFactory.sql().SELECT("*")
.FROM("score")
.$_$(
sqlFactory.sql().SELECT("DISTINCT score_value").FROM("score")
).WHERE()
.AND("score")
.IN()
.build();
//Генерируется SQL-запрос: SELECT * FROM score WHERE 1 = 1 AND score IN (SELECT DISTINCT score_value FROM score)
Примечание: для сложных SQL-запросов рекомендуется использовать прямое построение строк:
String sql="SELECT * FROM score WHERE 1 = 1 AND score IN (SELECT DISTINCT score_value FROM score)";
sqlFactory.sql().str(sql);
4.7 Использование AND и OR вместе
В запросе нет информации об использовании AND и OR вместе. Использование beanParameter метода и добавление параметра
Map<String, Object> param = new HashMap<>();
param.put("name", "李%");
sqlFactory.sql()
.SELECT("*")
.FROM("student")
.WHERE("name").LIKE(":name")
.AND("age > :age")
.beanParameter(param) // Устанавливаем один параметр DTO
.addParameterMapItem("age", 12) // Добавляем
.queryList(StudVO.class);
Использование varParameter метода — поддержка ? заполнителя и переменных параметров
SQL sql = sqlFactory.sql();
sql.INSERT_INTO("student", "id", "name", "age")
.VALUES("?", "?", "?")
.varParameter("123", "小明")
.varParameter(12)
.update();
T queryOne(Class<T> returnClassType)
— запрос одного результата строки, упакованного в объект. Параметр может быть String/Integer/Long/Short/BigDecimal/BigInteger/Float/Double/Boolean или любым классом POJO.Map<String, Object> queryMap()
— запрос одной строки результата, упакованной в карту.List<T> queryList(Class<T> returnClassType)
— запрос нескольких строк результатов, упакованных в список объектов.List<Map<String, Object>> queryMapList()
— запрос нескольких строк результатов, упакованных в массив карт.List<Object[]> queryArrayList()
— запрос результатов, упакованных в общий список массивов.ResultPage<T> queryPage(int page, int perPage, Class<T> returnClassType)
— страница запроса результатов.StudentVO — класс представления для запроса, содержит поля name и age. StudentDTO — класс параметров запроса, содержащий поле name.
// queryList может запрашивать список, который может быть списком базовых типов или списком объектов
List<String> strings = sqlFactory.sql().SELECT("name")
.FROM("student")
.queryList(String.class); // Здесь выполняется запрос списка и указывается тип возвращаемого значения
List<StudVO> studVOList = sqlFactory.sql().SELECT("name", "age")
.FROM("student")
.WHERE("name=:name")
.beanParameter(new StudentDTO()) // Устанавливается один параметр DTO
.queryList(StudVO.class); // Запрашивается список объектов
// queryOne может запросить одно значение, которое может быть базовым типом или объектом
String name = sqlFactory.sql().SELECT("name")
.FROM("student")
.WHERE("id=:id")
.AND("name=:name")
.mapItemsParameter("id", 12345) // Можно передать несколько значений k-v, также можно вызвать parameterMap для передачи параметра Map
.addParameterMapItem("name", "Jack")// Использование addParameterMapItem для добавления значений k-v
.queryOne(String.class); // Здесь выполняется запрос одного объекта (базовый тип) и указывается тип возвращаемого значения
StudVO studVO = sqlFactory.sql().SELECT("name", "age")
.FROM("student")
.WHERE("name=:name")
.beanParameter(new StudentDTO()) // Устанавливается один DTO
.queryOne(StudVO.class); // Запрос одного объекта
// queryPage запрос страницы
ResultPage<StudVO> studVOResultPage =sqlFactory.sql().SELECT("name", "age")
.FROM("student")
.queryPage(1, 10, StudVO.class); // Запрос страницы (первая страница, 10 записей на страницу)
// В соответствии с конкретной базой данных выполнить запрос страницы
ResultPage<StudVO> studVOResultPage =sqlFactory.sql().SELECT("name", "age")
.FROM("student")
.queryPage(1, 10, StudVO.class, DbType.MY_SQL);
Обратите внимание: после вызова queryOne, если запрошенное значение не существует, будет выброшено исключение EmptyResultDataAccessException, а не null, поэтому необходимо использовать тип упаковки для получения его значения вместо базового типа и проверять ненулевое значение.
Обратите внимание: queryPage возвращает объект ResultPage.
RowMapper — это интерфейс в Spring-jdbc, он может упаковывать данные каждой строки в пользовательский класс.
public interface RowMapper<T> {
/**
* Spring будет вызывать итерацию по результатам запроса и каждый раз вызывать этот метод для преобразования результатов запроса в объекты.
*/
T mapRow(ResultSet rs, int rowNum) throws SQLException;
}
Методы queryXXX в классе SQL поддерживают этот интерфейс, используйте следующим образом:
List<StudentVO> list
= sqlFactory.sql().SELECT("name", "age")
.FROM("student")
.queryList(new RowMapper<StudentVO>() {
@Override
public StudentVO mapRow(ResultSet rs, int rowNum) throws SQLException {
StudentVO studentVO = new StudentVO();
studentVO.setName(rs.getString("name"));
studentVO.setAge(rs.getInt("age"));
return studentVO;
}
});
Автоматическое связывание, имена столбцов и имена классов Java должны совпадать, например: атрибут «userName» может соответствовать полю базы данных «USERNAME» или «user_name». Таким образом, нам не нужно вручную привязывать их. Класс SQL использует этот класс при запросе результатов как составного объекта, и в большинстве случаев нет необходимости вызывать его вручную. ColumnMapRowMapper — реализация класса (spring-jdbc реализация).
Результаты упаковываются в виде карты. Большая часть SQL-класса queryMap/queryMapList использует этот класс, и в большинстве случаев нет необходимости вызывать его вручную.
SingleColumnRowMapper — реализация класса (spring-jdbc реализация).
Большая часть SQL-класса queryList/queryOne использует этот класс при получении результатов с одной колонкой, таких как List, List, Long, Date. В большинстве случаев нет необходимости вызывать его вручную.
PartialBeanPropertyRowMapper — реализация класса (fastsql реализация).
Может сопоставляться с классом BeanPropertyRowMapper, а остальное необходимо указывать вручную, при этом дочерний класс должен переопределить метод remainingMap.
CombinedBeanPropertyRowMapper — реализация класса (fastsql реализация, тестирование продолжается).
Сопоставляется со сложными результатами, используется вместе с аннотацией InnerBeanMapped.
Для операций вставки:
// вставка
sqlFactory.sql().INSERT_INTO("student", "id", "name", "age")
.VALUES(":id", ":name", ":age")
.mapItemsParameter("id", 678, "name", "Kiven", "age", 123)
.update();
Для операций изменения:
sqlFactory.sql().UPDATE("student")
.SET("name",":name")
.WHERE("id=678")
.mapItemsParameter("id", 678, "name", "Rose", "age", 123)
.update();
Для операции удаления:
sqlFactory.sql().DELETE_FROM("student")
.WHERE("id=:id")
.mapItemsParameter("id", 678)
.update();
Управление транзакциями вручную с помощью инструмента класса Spring org.springframework.jdbc.datasource.DataSourceUtils
:
Connection connection = DataSourceUtils.getConnection(dataSource);// открыть транзакцию
connection.setAutoCommit(false);// отключить автоматическую фиксацию
sqlFactory.sql()
.INSERT_INTO("sys_users", "id").VALUES(":id")
.mapItemsParameter("id", 456)
.update();
sqlFactory.sql()
.INSERT_INTO("sys_users", "id").VALUES(":id")
.mapItemsParameter("id", 234)
.update();
//connection.rollback(); // откатить
connection.commit();// зафиксировать транзакцию
Используются следующие аннотации:
@Table
— необязательная, если не указана, будет проанализирована как student (в соответствии с формой имени класса с подчёркиванием).@Id
— обязательная, соответствует первичному ключу таблицы.@Entity
— необязательная, рекомендуется для совместимости со стандартом JPA.Пример:
@Entity
@Table(name="student")
@Data //use lombok
public class Student {
@Id
private Integer id;
private String name;
private Integer age;
private LocalDate birthday;
private String homeAddress;
}
Создайте новый класс DAO слоя доступа к данным, наследуя от BaseDAO, чтобы автоматически наследовать методы BaseDAO (см. часть 2).
Класс DAO уровня:
@Repository
public class StudentDAO extends BaseDAO<Student,Integer> {
}
Если SQLFactory настроен как Spring @Bean, он будет автоматически внедрён. В сервисе вы можете использовать этот DAO:
@Service
public class StudentService {
@Autowire
private StudentDAO studentDAO;
@Transactional //если требуется транзакция--org.springframework.transaction.annotation.Transactional
public void test1(){
studentDAO.XXX();//вызов любого метода
}
}
public class StudentDAO extends BaseDAO<Student,String> {
}
public class Test {
public static void main(String[] args) {
SQLFactory sqlFactory = ...
StudentDAO studentDAO= new StudentDAO();
studentDAO.setSqlFactory(sqlFactory);//вручную внедрить
//выполнить операцию
studentDAO.XXX();
}
}
CRUD — это аббревиатура четырёх основных операций с данными: C означает создание, R — чтение, U — обновление, D — удаление. BaseDAO автоматически создаёт методы обработки данных в таблице.
Метод int insert(E entity)
вставляет значения объекта в базу данных, значения null будут установлены в NULL в сгенерированном SQL-запросе.
Student student = new Student();
student.setId(2);
student.setName("小丽");
student.setBirthday(LocalDate.now());//здесь используется тип времени jdk8
student.setHomeAddress("");
studentDao.insert(student);//получить сохранённый идентификатор
//эквивалентный SQL-запрос (обратите внимание, что возраст установлен в null)
//INSERT INTO student(id,name,age,birthday,home_address) VALUES (2,'小丽',NULL,'2017-07-11','')
Метод int insertSelective(E entity)
, вставляет в базу данных значения объекта, отличные от null.
Student student = new Student();
student.setId(3);
student.setName("小丽");
student.setBirthday(new Date());
student.setHomeAddress("");
studentDao.insertSelective(student);
//эквивалентный SQL-запрос (обратите внимание на то, что возраст не сохраняется, в слое базы данных возраст будет сохранён как значение по умолчанию для таблицы, если значение по умолчанию не установлено, оно будет сохранено как null)
//===>INSERT INTO student(id,name,birthday,home_address) VALUES (3,'小丽','2017-07-11','')
Метод int update(E entity)
, обновляет данные на основе объекта (поля null в базе данных будут установлены в null), поле @id объекта не может быть пустым.
//ожидает обновления
Метод int updateSelective(E entity)
, обновляет данные на основе объекта (обновляются только поля объекта, отличные от null), поле @id объекта не может быть пустым.
//ожидает обновления
Метод int updateByColumn(E entity, String... columns)
, обновляет столбцы, указанные параметрами columns, на основе идентификатора, поле @id объекта не может быть пустым.
Student student = studentDAO.selectOneById(44);
student.setAge(19);
studentDAO.updateByColumn(student,"age");
//===>UPDATE student SET age=? WHERE id=?
``` ### Данные удаление
**Метод `int deleteOneById(String id)`** — согласно идентификатору удаляет данные.
```java
int num = studentDao.deleteOneById(2);//получение количества удалённых строк
//===>DELETE FROM student WHERE id=2
Метод int deleteAll()
— удаляет все строки из таблицы.
int number = studentDao.deleteAll();//получение количества удалённых строк
// ===>DELETE FROM student
Метод int[] deleteInBatch(List<String> ids)
— удаляет данные в пакетном режиме согласно списку идентификаторов (все операторы удаления будут отправлены в базу данных одновременно).
List<String> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
studentDao.deleteInBatch(ids);//возвращение количества успешных удалений
Метод int deleteWhere(String sqlCondition, Object... values)
— удаление согласно условию.
**Метод E selectOneById(String id)**
— поиск объекта по идентификатору.
Student student = studentDao.selectOneById(4);//поиск данных с id 12345678 и их упаковка в класс Student
Метод E selectOneWhere(String sqlCondition, Object... values)
, E selectOneByEntity(E entity)
— поиск по условию или сущности.
Student student = studentDao.selectOneWhere("name=? AND home_address=?", "小明", "成都");
**Методы E selectOneWhere(String sqlCondition, SqlParameterSource parameterSource)
и E selectByEntity(E entity)**
— запрос одной записи.
**Метод List<E> selectWhere(String sqlCondition, Object... values)**
— возвращает одну или несколько записей, максимальное количество параметров — три.
List<Student> studentList = studentDao.selectWhere("name=?", "小明");
List<Student> studentList = studentDao.selectWhere("ORDER BY age");
List<Student> studentList = studentDao.selectWhere("home_address IS NULL ORDER BY age DESC");
//...
Метод List<E> selectAll()
— возвращает все записи.
List<Student> allStudents = studentDao.selectAll();
Метод List<E> selectWhere(String sqlCondition, SqlParameterSource parameterSource), List<E> selectByEntity(E entity)
— возвращает одну или несколько записей.
Метод ResultPage<E> selectPageWhere(String sqlCondition, int pageNumber, int perPage, Object... values), ResultPage<E> selectPage(int pageNumber, int perPage)
— пагинация.
Метод int countWhere(String sqlCondition, Object... values)
— подсчёт записей согласно условию.
int countWhere = studentDao.countWhere("age >= 20"); //поиск студентов старше 20 лет
int countWhere = studentDao.countWhere("age > ?" , 10); //поиск студентов, возраст которых больше 10
**Метод int countWhere(String sqlCondition, SqlParameterSource parameterSource)**
— подсчёт согласно условию.
@Repository
public class BizPhotoDAO extends ApplicationBaseDAO<BizPhotoPO, String> {
public int countByName() {
return countWhere("photo_name=:name", new MapSqlParameterSource().addValue("name", "物品照片"));
}
}
Метод int count()
— подсчет общего количества записей в таблице.
Рекомендуется реализовать собственный ApplicationBaseDAO в своей программе, что позволит:
public abstract class ApplicationBaseDAO<E, ID> extends BaseDAO<E, ID> {
//добавление методов и т. д.
}
////Наш StudentDAO теперь должен наследовать от ApplicationBaseDAO
@Repository
public class StudentDAO extends ApplicationBaseDAO<Student,Integer> {
}
Например, добавлен метод logicDelete для логического удаления, который будет применяться ко всем DAO, которые его наследуют.
public abstract class ApplicationBaseDAO<E, ID> extends BaseDAO<E, ID> {
//...другие методы
public void logicDelete(ID id) {
//для каждой таблицы есть столбец defunct, 1 означает (логически) удалено
namedParameterJdbcTemplate.getJdbcOperations().update("UPDATE " + this.tableName + " SET defunct = 1");
}
//...другие методы
}
В методе logicDelete используется переменная tableName. В классе BaseDAO доступны следующие переменные:
Class<E> entityClass; //класс сущности DAO
Class<ID> idClass; //тип первичного ключа, помеченного @Id
Logger log; //журнал, можно использовать непосредственно в классе реализации
String className; //имя класса сущности
String tableName; //имя таблицы
Field idField; //@Id соответствует полю ссылки
String idColumnName; //имя столбца первичного ключа
namedParameterJdbcTemplate //шаблон jdbc
//...ожидает обновления
public abstract class OracleApplicationBaseDAO<E, ID> extends BaseDAO<E, ID> {
//переопределение метода setSqlFactory
@Autowired
@Qualifier("sqlFactory1")//===>внедрение по имени
@Override
protected void setSqlFactory(SQLFactory sqlFactory) {
super.setSqlFactory(sqlFactory);
}
}
public abstract class MySqlApplicationBaseDAO<E, ID> extends BaseDAO<E, ID> {
//переопределение метода setSqlFactory
@Autowired
``` ### Настройка перехватчиков в BaseDAO
```java
@Qualifier("sqlFactory2")//===>根据名称注入
@Override
protected void setSqlFactory(SQLFactory sqlFactory) {
super.setSqlFactory(sqlFactory);
}}
}
public abstract class ApplicationBaseDAO<E, ID> extends BaseDAO<E, ID> {
public ApplicationBaseDAO() {
// 1.Настройка триггера
this.useBeforeInsert = true; //Перед вставкой
this.useBeforeUpdate = true; //Перед обновлением
}
//2.Переписываем методы триггеров
@Override
protected void beforeInsert(E object) {
EntityRefelectUtils.setFieldValue(object, "createdAt", LocalDateTime.now());
EntityRefetectUtils.setFieldValue(object, "updatedAt", LocalDateTime.now());//При вставке данных автоматически записываются createdAt и updatedAt
}
@Override
protected void beforeUpdate(E object) {
EntityReflectUtils.setFieldValue(object, "updatedAt", LocalDateTime.now());//При обновлении данных автоматически обновляется updatedAt
}
}
Соответствующие отношения:
count — параметр, который показывает количество успешных выполнений.
Включение | Метод, требующий перезаписи | Воздействие |
---|---|---|
useBeforeInsert | beforeInsert (E entity) | insertSelective (..)/insert (..) выполняется перед вставкой |
useAfterInsert | afterInsert (E entity, int count) | insertSelective (..)/insert (..) выполняется после вставки |
useBeforeUpdate | beforeUpdate (E entity) | updateSelective (..)/update (..) выполняется перед обновлением |
useAfterUpdate | afterUpdate (E entity, int count) | updateSelective (..)/update (..)/updateByColumn (..) выполняется после обновления |
useBeforeDelete | beforeDelete (ID id) | deleteOneById (..) выполняется до удаления |
useAfterDelete | void afterDelete (ID id, int count) | deleteOneById (..) выполняется после удаления |
В BaseDAO интегрирован SQL-конструктор, в унаследованном от него классе вы можете напрямую вызвать getSQL()
, чтобы получить экземпляр SQL:
@Repository
public class StudentDAO extends ApplicationBaseDAO<Student, String> {
/**
* Запрос списка студентов по имени
*/
public List<Student> queryListByName() {
return getSQL().SELECT("*").FROM(this.tableName)
.WHERE("name").LIKE("'李%'")
.queryList(Student.class);//Запрос списка
}
/**
* Изменить имя студента на основе старого имени
*/
public int updateName(String oldName,String newName) {
return getSQL().UPDATE(this.tableName).SET("name = '"+newName+"'").WHERE("name").eqByType(oldName).update();
}
}
FastSQLUtils.getInClause(Collection<?> collection)
автоматически определяет, какой разделитель использовать, исходя из типа Collection:
FastSQLUtils.getInClause(Lists.newArrayList(1, 23, 4, 15));
//Генерирует=>(1,23,4,15)
FastSQLUtils.getInClause(Lists.newArrayList("dog", "people", "food", "apple"));
//Генерирует=> ('dog','people','food','apple')
Примечание: функция IN уже интегрирована в метод IN SQL-конструктора.
FastSqlUtils.bothWildcard("李"); // => %李%
FastSqlUtils.leftWildcard("李"); // => %��ли
FastSqlUtils.rightWildcard("李"); // => ��ли%
Чтобы отобразить журнал SQL, необходимо настроить соответствующий уровень журнала для соответствующих классов: org.springframework.jdbc.core.JdbcTemplate — настройка уровня журнала на debug покажет операторы SQL. org.springframework.jdbc.core.StatementCreatorUtils — настройка уровня журнала на trace покажет процесс привязки параметров.
Вот конфигурация Springboot:
#Отображение SQL
logging.level.org.springframework.jdbc.core.JdbcTemplate=debug
#Отображение связанных параметров
logging.level.org.springframework.jdbc.core.StatementCreatorUtils=trace
Добавлены методы selectByEntity и selectOneByEntity в BaseDAO.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )