https://github.com/babyblue94520/hi-sql
Use SQL like Spring Data JPA
https://github.com/babyblue94520/hi-sql
hi-sql jpa orm spring-data-jpa sql
Last synced: 7 months ago
JSON representation
Use SQL like Spring Data JPA
- Host: GitHub
- URL: https://github.com/babyblue94520/hi-sql
- Owner: babyblue94520
- License: apache-2.0
- Created: 2021-04-15T09:58:20.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2025-08-28T08:19:04.000Z (8 months ago)
- Last Synced: 2025-08-28T15:33:58.819Z (8 months ago)
- Topics: hi-sql, jpa, orm, spring-data-jpa, sql
- Language: Java
- Homepage:
- Size: 1.41 MB
- Stars: 6
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Hi SQL
[中文](README.zh-TW.md)
## Overview


A simple and highly flexible pure __SQL__ library.
There are many __ORM Frameworks__ available, and different projects may use different __ORMs__. When using them, you
need to design __SQL__ based on requirements, convert it into the corresponding __ORM__ syntax, and ensure that the _
_ORM__ generates the expected __SQL__. Special __SQL__ cases require extra effort to convert to __ORM__ syntax, and some
need adjustments based on the database being used. The pros and cons of __ORMs__ are well known, so they won't be
discussed further here.
## Requirements
* Spring Framework 5+
* Java 11+
## Features
* Primarily __Native SQL__
* High performance
* Provides basic parameterized queries and dynamic __SQL__ substitution
* Maps query results to any __Java__ object
* Supports __Spring @Transactional__
## Quick Start
### Configuration
By default, it scans all __Interfaces__ annotated with __@Repository__ within the same __Package__.
[HiSqlConfig.java](src/test/java/pers/clare/hisql/data/HiSqlConfig.java)
```java
@EnableHiSql
public class HiSqlConfig {
}
```
### Create Entity and Interface
* __SQLCrudRepository__
Extend __SQLCrudRepository__ to get basic INSERT, UPDATE, DELETE, and SELECT functionalities for an __Entity__.
[User.java](src/test/java/pers/clare/hisql/data/entity/User.java)
[UserRepository.java](src/test/java/pers/clare/hisql/data/repository/UserRepository.java)
```java
@Repository
public interface UserRepository extends SQLCrudRepository {
}
```
* __SQLRepository__
Extend __SQLRepository__ to create a lightweight __Repository__.
### Usage
```java
@Service
public class UserService {
private UserRepository userRepository;
public User find(Long id) {
if (id == null) return null;
return userRepository.findById(id);
}
}
```
## Features
* Parameterization
* Standard parameters
```java
@Repository
public interface DemoRepository extends SQLRepository {
@HiSql("select * from test where value=:value")
List findAll(String value);
}
```
* Object parameters
Converts an object into parameters like __id__, __obj.id__, __name__, __obj.name__. If duplicate parameter names
exist, they are overwritten in order.
```java
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ValueObject{
private Integer id;
private String name;
}
@Repository
public interface DemoRepository extends SQLRepository {
@HiSql("""
select *
from test
where name=:obj.name
limit 1
""")
ValueObject findAll(ValueObject obj);
@HiSql("select * from test where name=:obj.name")
List findAll(ValueObject obj);
@HiSql("select * from test where name=:name")
List findAll2(ValueObject obj);
}
```
* Dynamic __SQL__ Substitution
Use this method when dynamically adding conditions or replacing __SQL__ strings.
Avoid manual __SQL__ concatenation externally to prevent __SQL Injection__. Follow the example below.
```java
@Repository
public interface DemoRepository extends SQLRepository {
@HiSql("select * from test where 1=1 {valueCondition}")
List> findAll(String valueCondition, String value);
@HiSql("select * from test where 1=1 {value}")
List> findAll(SqlReplace value);
}
@Service
public class DemoService {
private DemoRepository demoRepository;
public void findAll(String value){
// Simple string substitution
demoRepository.findAll("and column = :value", value);
// Using SqlReplace, if value is null, it is replaced with blank, otherwise, it is substituted along with the value parameter
demoRepository.findAll(SqlReplace.of(value," and column = :value"));
}
}
```
* Read __SQL__ from __XML__
* The default root directory is __resources/hisql/__, where an __XML__ file with the same name as the __Class__
should be created.
Example: `resources/hisql/CustomRepository.xml`
* Create a __Tag__ with the same name as the **Method Name** or use __@HiSql(name=...)__ to specify a __Tag__.
```xml
```
* More examples in tests
[CustomRepository.java](src/test/java/pers/clare/hisql/data/repository/CustomRepository.java)
## Advanced
* ### Pagination Optimization
Use an initially calculated total or an estimated value to avoid repeatedly calculating the total when paginating. If
precise totals are required, this method is not recommended.
```java
Pagination pagination = Pagination.of(0,20);
Page page = repository.page(pagination);
pagination = Pagination.of(page.getPage() + 1, page.getSize(), page.getTotal());
repository.page(pagination);
```
* ### Virtual Total Count
In pagination mode, using __select count(*)__ to query the total count can be very slow. Estimating the total count
avoids scanning the entire result set.
### Usage
```java
pagination.setVirtualTotal(true);
```
### Implementation
* MySQL
Replace the actual count (*) with the explain result "rows".
```java
@Override
public long getVirtualTotal(
Pagination pagination
, Connection connection
, String sql
, Object[] parameters
) throws SQLException {
String totalSql = "explain select count(*) from(" + sql + ")t";
ResultSet rs = ConnectionUtil.query(connection, totalSql, parameters);
if (rs.next()) {
return rs.getLong("rows");
} else {
throw new HiSqlException(String.format("query total error.(%s)", totalSql));
}
}
```
* ### Modifying __PaginationMode__
### Configuration
```java
@EnableHiSql(
paginationMode = MySQLPaginationMode.class
)
public class Demo2HiSqlConfig {
}
```
### Custom Implementation
```java
public class CustomPaginationMode implements PaginationMode {
public void appendPaginationSQL(
StringBuilder sql
, Pagination pagination
) {
appendSortSQL(sql, pagination.getSorts());
sql.append(" limit ")
.append(pagination.getSize() * pagination.getPage())
.append(',')
.append(pagination.getSize());
}
@Override
public long getVirtualTotal(
Pagination pagination
, Connection connection
, String sql
, Object[] parameters
) throws SQLException {
// TODO
}
}
```
* ### Modifying NamingStrategy
### Configuration
```java
@EnableHiSql(
naming = UpperCaseNamingStrategy.class
)
public class Demo2HiSqlConfig {
}
```
### Custom Implementation
```java
public class CustomNamingStrategy implements NamingStrategy{
}
@EnableHiSql(
naming = CustomNamingStrategy.class
)
public class Demo2HiSqlConfig {
}
```
* ### Custom ResultSetConverter
Converts ResultSet Value to the target special type.
### Custom Implementation
```java
public class CustomResultSetConverter extends ResultSetConverter {
{
register(Pattern.class, (rs, i) -> Pattern.compile(rs.getString(i)));
}
}
```
### Configuration
```java
@EnableHiSql(
resultSetConverter = CustomResultSetConverter.class
)
public class HiSqlConfig {
}
```