Ceci est une introduction à la bibliothèque de persistance DB de Java "uroboroSQL", dans laquelle l'auteur lui-même est impliqué en tant que committer.
https://github.com/future-architect/uroborosql
Dans le développement de systèmes d'entreprise, il est encore souvent réalisé en Java et, en raison des caractéristiques du système, RDB est souvent utilisé.
L'attention se concentre sur des produits tels que Amazon Aurora et Cloud Spanner. Je pense que la raison pour laquelle ils se rassemblent est qu'ils ont la particularité de renverser le théorème CAP selon lequel ils veulent utiliser à la fois les transactions et SQL, bien qu'ils souhaitent étendre la base de données en parallèle et distribuée au fur et à mesure que les temps changent.
J'ai posté un article le 24 décembre de l'année dernière Essayez de charger CockroachDB la veille de Noël, et ce CockroachDB est aussi un tel idéal. La nécessité d'enseigner les avantages de NoSQL avec RDB est un rêve que les ingénieurs aspirent:
Les systèmes créés avec Java au début des années 2000 utilisaient souvent l'API JDBC telle quelle, mais après cela, des mappeurs OR (tels que Hibernate, iBatis (actuellement MyBatis) et S2Dao du projet Seaser) ORM) a été développé et est maintenant utilisé.
Après cela, JPA (Java Persistence API) 1.0 a été formulé en tant que framework de persistance standard Java en 2006, JPA 2.0 en 2009, JPA 2.1 en 2013 et Java SE peut également être utilisé, mais Java EE C'est une situation où elle continue d'évoluer avec l'EJB de.
Pour la dernière comparaison de bibliothèques, l'article Discussion sur Java Persistence Framework 2017 (1) est très utile (désolé). Cependant, le SQL uroboro que je vais vous présenter n'est pas inclus: cry :).
uroboroSQL est l'une des bibliothèques de persistance DB en Java, et adopte fondamentalement une approche qui complète le manque de SQL avec Java plutôt que de générer du SQL à partir de Java.
Bien sûr, il est difficile d'écrire SQL un par un avec INSERT / UPDATE / DELETE d'un enregistrement, nous fournissons donc également une API en tant qu'ORM.
Vous pouvez l'essayer immédiatement sans construire lors du développement avec 2Way-SQL.
Il est possible d'agréger les branches conditionnelles d'instructions SQL et d'effectuer des rapports de couverture.
article | Prise en charge d'uroboro SQL |
---|---|
Licence | MIT |
Système | OSS |
latest | v0.5 (2017/12) |
Externalisation SQL | ○ |
DSL | × |
Java | 8<= |
Compatible Stream Lambda | ○ |
Génération automatique d'entité | ○ |
Correspondance avec la valeur de division | ○ (L'énumérateur et la classe constante sont acceptables) |
Appel de procédure stockée | ○ |
Personnalisation de ResultSet | ○ |
Oracle | ○ |
DB2 | - |
MySQL | ○ |
PostgreSQL | ○ |
MariaDB | - |
MS-SQL | ○ |
H2 | ○ |
Derby | ○ |
Sybase | - |
SQLite | ○ |
Dépendance | commons-lang3,slf4,ognl,jline |
Maintenant, pour comprendre la bibliothèque, il est rapide de voir quel type d'implémentation il s'agira lors de son utilisation. Donc, j'ai rassemblé un échantillon d'implémentations fréquemment utilisées.
À propos, au moment de la rédaction de cet article, il peut être plus abondant que le document officiel: sweat_smile:
SqlConfig config = UroboroSQL.builder("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "sa", "sa").build();
try (SqlAgent agent = config.agent()) {
agent.required(() -> {
// insert/update/delete
});
}
2way-SQL
department/select_department.sql
SELECT /* _SQL_ID_ */
DEPT.DEPT_NO AS DEPT_NO
, DEPT.DEPT_NAME AS DEPT_NAME
FROM
DEPARTMENT DEPT
WHERE
1 = 1
/*IF SF.isNotEmpty(dept_no)*/
AND DEPT.DEPT_NO = /*dept_no*/1
/*END*/
/*IF SF.isNotEmpty(dept_name)*/
AND DEPT.DEPT_NAME LIKE '%' || /*dept_name*/'' || '%'
/*END*/
department/insert_department.sql
INSERT /* _SQL_ID_ */
INTO
DEPARTMENT
(
DEPT_NO
, DEPT_NAME
) VALUES (
/*dept_no*/1
, /*dept_name*/'sample'
)
department/update_department.sql
UPDATE /* _SQL_ID_ */
DEPARTMENT DEPT
SET
DEPT.DEPT_NAME = /*dept_name*/'sample'
DEPT.LOCK_VERSION = DEPT.LOCK_VERSION + 1
WHERE
DEPT.DEPT_NO = /*dept_no*/1
AND DEPT.LOCK_VERSION = /*lock_version*/0
department/delete_department.sql
DELETE /* _SQL_ID_ */
FROM
DEPARTMENT DEPT
WHERE
DEPT.DEPT_NO = /*dept_no*/1
Avec la même syntaxe que S2Dao etc., vous pouvez décrire les branches avec une notation de commentaire en SQL.
try (SqlAgent agent = config.agent()) {
List<Map<String, Object>> deptList =
agent.query("department/select_department")
.param("dept_name", "retail")
.collect();
}
try (SqlAgent agent = config.agent()) {
Stream<Map<String, Object>> depts =
agent.query("department/select_department")
.param("dept_name", "retail")
.stream();
}
try (SqlAgent agent = config.agent()) {
Stream<Department> depts =
agent.query("department/select_department")
.param("dept_name", "retail")
.stream(Department.class);
}
try (SqlAgent agent = config.agent()) {
Map<String, Object> dept =
agent.query("department/select_department")
.param("dept_no", 1001)
.first();
}
try (SqlAgent agent = config.agent()) {
Department dept =
agent.query("department/select_department")
.param("dept_no", 1001)
.first(Department.class);
}
try (SqlAgent agent = config.agent()) {
Map<String, Object> dept =
agent.query("department/select_department")
.param("dept_no", 1001)
.findFirst()
.orElse(null);
}
try (SqlAgent agent = config.agent()) {
Department dept =
agent.query("department/select_department")
.param("dept_no", 1001)
.findFirst(Department.class)
.orElse(null);
}
INSERT/UPDATE/DELETE
try (SqlAgent agent = config.agent()) {
agent.required(() -> {
// insert
agent.update("department/insert_department")
.param("dept_no", 1001)
.param("dept_name", "sales")
.count();
// update
agent.update("department/update_department")
.param("dept_no", 1001)
.param("dept_name", "HR")
.count();
// delete
agent.update("department/delete_department")
.param("dept_no", 1001)
.count();
});
}
List<Map<String, Object>> inputList = new ArrayList<>();
//Omission
try (SqlAgent agent = config.agent()) {
agent.required(() -> {
agent.batch("department/insert_department")
.paramStream(inputList.stream())
.count();
});
}
On suppose que vous disposez de la classe de modèle suivante.
@Table(name = "DEPARTMENT")
public class Department {
private int deptNo;
private String deptName;
@Version
private int lockVersion = 0;
//Getter omis/setter
}
Le champ avec @Version est reconnu par uroboroSQL comme information de version pour le verrouillage optimiste, +1 dans la clause SET au moment de UPDATE, ajouté à la condition de recherche de la clause WHERE, et SQL est émis, et le nombre de mises à jour est de 0. Déclenche ʻOptimisticLockException`.
try (SqlAgent agent = config.agent()) {
Department dept =
agent.find(Department.class, 1001).orElse(null);
}
À partir de la version 0.5.0, seule la recherche par clé primaire de table unique est disponible dans l'interface DAO, mais dans la dernière mise à niveau de version, il sera possible de spécifier des conditions de recherche équivalentes à la clause WHERE dans une seule table.
INSERT
try (SqlAgent agent = config.agent()) {
Department hrDept = new Department();
hrDept.setDeptNo(1002);
hrDept.setDeptName("HR");
agent.insert(hrDept);
}
UPDATE
try (SqlAgent agent = config.agent()) {
agent.required(() -> {
Department dept =
agent.find(Department.class, 1001).orElseThrow(Exception::new);
dept.setDeptName("Human Resources");
agent.update(dept);
});
}
DELETE
try (SqlAgent agent = config.agent()) {
agent.required(() -> {
Department dept =
agent.find(Department.class, 1001).orElseThrow(Exception::new);
agent.delete(dept);
});
}
--uroboroSQL document japonais - https://future-architect.github.io/uroborosql-doc/ --Introduction d'uroboroSQL (OSC2017 Nagoya) #oscnagoya - https://www.slideshare.net/KenichiHoshi1/uroborosql-osc2017-nagoya-oscnagoya --uroboroSQL générateur de source - https://github.com/shout-star/uroborosql-generator --uroboroSQL exemple d'application CLI - https://github.com/future-architect/uroborosql-sample --exemple d'application web uroboroSQL (avec Spring Boot) - https://github.com/shout-star/uroborosql-springboot-demo
Recommended Posts