# hasordb **Repository Path**: BI4PWI/hasordb ## Basic Information - **Project Name**: hasordb - **Description**: HasorDB 是一个全功能数据库访问工具,提供对象映射、丰富的类型处理、动态SQL、存储过程、内置分页方言20+、支持嵌套事务、多数据源、条件构造器、INSERT 策略、多语句/多结果。并兼容 Spring 及 MyBatis 用法。它不依赖任何其它框架,因此可以很方便的和任意一个框架整合在一起使用。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: http://www.hasor.cn/ - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 74 - **Created**: 2021-12-29 - **Last Updated**: 2021-12-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 介绍 ------------------------------------ ``Documents are translated using translation software, The original for README.md`` * Project Home: [https://www.hasordb.net(备案中)](https://www.hasordb.net) [http://www.hasor.cn/en/(临时地址)](http://www.hasor.cn/en/) * [![QQ群:948706820](https://img.shields.io/badge/QQ%E7%BE%A4-948706820-orange)](https://qm.qq.com/cgi-bin/qm/qr?k=Qy3574A4VgI0ph4fqFbZW-w49gnyqu6p&jump_from=webapi) [![zyc@byshell.org](https://img.shields.io/badge/Email-zyc%40byshell.org-blue)](mailto:zyc@byshell.org) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/net.hasor/hasor-db/badge.svg)](https://maven-badges.herokuapp.com/maven-central/net.hasor/hasor-db)   HasorDB is a Full-featured database access tool, Providing object mapping,Richer type handling than Mybatis, Dynamic SQL, stored procedures, more dialect 20+, nested transactions, multiple data sources, conditional constructors, INSERT strategies, multiple statements/multiple results. And compatible with Spring and MyBatis usage. It doesn't depend on any other framework, so it can be easily integrated with any framework. Features ------------------------------------ - Familiar - JdbcTemplate(like Spring JDBC) - Mapper files(Compatible with most MyBatis) - LambdaTemplate (Close to the MyBatis Plus、jOOQ and BeetlSQL) - @Insert、@Update、@Delete、@Query、@Callable (like JPA) - Transaction support - Support for 5 transaction isolation levels, 7 transaction propagation behaviors (same as Spring TX) - provides TransactionTemplate and TransactionManager transaction control (same usage as Spring) - Feature - Support for paging queries and multiple database dialects (20+) - Support for INSERT strategies (INTO, UPDATE, IGNORE) - Richer TypeHandler(MyBatis 40+,HasorDB 60+) - Mapper file supports multiple statements and multiple results - provides special '@{XXX, expr, XXXXX}' rule extension mechanism to make dynamic SQL simpler - Support for stored procedures - Supports time types in JDBC 4.2 and Java8 - Support for multiple data sources Quick Start ------------------------------------ dependency ```xml net.hasor hasor-db 4.3.0 ``` database drivers, for example: ```xml mysql mysql-connector-java 8.0.22 ``` HasorDB can be used without relying on database connection pools, but having a database connection pool is standard for most projects. Druid of Alibaba ```xml com.alibaba druid 1.1.23 ``` Finally, prepare a database table and initialize some data (' createdB.sql 'file) ```sql drop table if exists `test_user`; create table `test_user` ( `id` int(11) auto_increment, `name` varchar(255), `age` int, `create_time` datetime, primary key (`id`) ); insert into `test_user` values (1, 'mali', 26, now()); insert into `test_user` values (2, 'dative', 32, now()); insert into `test_user` values (3, 'jon wes', 41, now()); insert into `test_user` values (4, 'mary', 66, now()); insert into `test_user` values (5, 'matt', 25, now()); ``` ### using SQL Using SQL to read data 'PrintUtils' and' DsUtils' can be found in the example project ```java // creating a data source DataSource dataSource = DsUtils.dsMySql(); // create JdbcTemplate object JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); // load the test data script jdbcTemplate.loadSQL("CreateDB.sql"); // Query the data and return it as a Map List> mapList = jdbcTemplate.queryForList("select * from test_user"); // print daa PrintUtils.printMapList(mapList); ``` console results: ```text /--------------------------------------------\ | id | name | age | create_time | |--------------------------------------------| | 1 | mali | 26 | 2021-11-12 19:14:06.0 | | 2 | dative | 32 | 2021-11-12 19:14:06.0 | | 3 | jon wes | 41 | 2021-11-12 19:14:06.0 | | 4 | mary | 66 | 2021-11-12 19:14:06.0 | | 5 | matt | 25 | 2021-11-12 19:14:06.0 | \--------------------------------------------/ ``` If you want to receive data using a DTO object, you need to create a DTO object. ```java // If the attribute and column names match exactly, no annotations are required. // - This column is simply declared with the @table annotation, since the Table name and column name of 'test_user' match the hump underline. // - If you need to map Table and Column names please refer to @table, @column for more attributes @Table(mapUnderscoreToCamelCase = true) public class TestUser { private Integer id; private String name; private Integer age; private Date createTime; // getters and setters omitted } // Then use the 'queryForList' method to query directly, and the console can get the same result List dtoList = jdbcTemplate.queryForList("select * from test_user", TestUser.class); PrintUtils.printObjectList(dtoList); ``` ### using CURD for single-table CURD operations, you can use 'LambdaTemplate', it is a subclass of 'JdbcTemplate' ```java // creating a data source DataSource dataSource = DsUtils.dsMySql(); // create LambdaTemplate object LambdaTemplate lambdaTemplate = new LambdaTemplate(dataSource); // load the test data script lambdaTemplate.loadSQL("CreateDB.sql"); // Query, all data List dtoList = lambdaTemplate.lambdaQuery(TestUser.class) .queryForList(); PrintUtils.printObjectList(dtoList); // Insert new data TestUser newUser = new TestUser(); newUser.setName("new User"); newUser.setAge(33); newUser.setCreateTime(new Date()); int result = lambdaTemplate.lambdaInsert(TestUser.class) .applyEntity(newUser) .executeSumResult(); // Update, update name from Mali to mala TestUser sample = new TestUser(); sample.setName("mala"); int result = lambdaTemplate.lambdaUpdate(TestUser.class) .eq(TestUser::getId, 1) .updateToBySample(sample) .doUpdate(); // Delete data whose ID is 2 int result = lambdaTemplate.lambdaUpdate(TestUser.class) .eq(TestUser::getId, 2) .doDelete(); ``` ### using DAO Using DAOs, you can extends from the 'BaseMapper' for generic DAO to perform some basic operations, again using the single-table CRUD example. ```java // Some of the DAO's interfaces need to recognize ID attributes, // so it is necessary to mark them with the @column annotation on the DTO object @Table(mapUnderscoreToCamelCase = true) public class TestUser { @Column(primary = true) private Integer id; private String name; private Integer age; private Date createTime; // getters and setters omitted } // creating a data source DataSource dataSource = DsUtils.dsMySql(); // Creating a BaseMapper DalSession session = new DalSession(dataSource); BaseMapper baseMapper = session.createBaseMapper(TestUser.class); // load the test data script baseMapper.template().loadSQL("CreateDB.sql"); // Query, all data List dtoList = baseMapper.query().queryForList(); PrintUtils.printObjectList(dtoList); // Insert new data TestUser newUser = new TestUser(); newUser.setName("new User"); newUser.setAge(33); newUser.setCreateTime(new Date()); int result = baseMapper.insert(newUser); // Update, update name from Mali to mala TestUser sample = baseMapper.queryById(1); sample.setName("mala"); int result = baseMapper.updateById(sample); // Delete data whose ID is 2 int result = baseMapper.deleteById(2); ``` As a DAO, you can define your own methods and configure the SQL statements to be executed through annotations. ```java // BaseMapper is optional, and inheriting it is equivalent to adding an extended set of single-table curds. @SimpleMapper public interface TestUserDAO extends BaseMapper { @Insert("insert into `test_user` (name,age,create_time) values (#{name}, #{age}, now())") public int insertUser(@Param("name") String name, @Param("age") int age); @Update("update `test_user` set age = #{age} where id = #{id}") public int updateAge(@Param("id") int userId, @Param("age") int newAge); @Delete("delete from `test_user` where age > #{age}") public int deleteByAge(@Param("age") int age); @Query(value = "select * from `test_user` where #{beginAge} < age and age < #{endAge}", resultType = TestUser.class) public List queryByAge(@Param("beginAge") int beginAge, @Param("endAge") int endAge); } ``` ```java // Create DalRegistry and register the TestUserDAO DalRegistry dalRegistry = new DalRegistry(); dalRegistry.loadMapper(TestUserDAO.class); // Create a Session using DalRegistry DalSession session = new DalSession(dataSource, dalRegistry); // Creating the DAO Interface TestUserDAO userDAO = session.createMapper(TestUserDAO.class); ``` ### using Mapper The best place for unified SQL management is still Mapper files, and HasorDB Mapper files are highly compatible with MyBatis at a very low learning cost. ```java // Use the @RefMapper to associate Mapper files with interface classes (extends from BaseMapper is optional) @RefMapper("/mapper/quick_dao3/TestUserMapper.xml") public interface TestUserDAO extends BaseMapper { public int insertUser(@Param("name") String name, @Param("age") int age); public int updateAge(@Param("id") int userId, @Param("age") int newAge); public int deleteByAge(@Param("age") int age); public List queryByAge(@Param("beginAge") int beginAge, @Param("endAge") int endAge); } ``` In order to better understand and use HasorDB Mapper files, it is recommended to add DTD validation. In addition HasorDB compatible with MyBatis3 DTD for most of the MyBatis project can be normally compatible. ```xml name,age,create_time insert into `test_user` ( ) values ( #{name}, #{age}, now() ) update `test_user` set age = #{age} where id = #{id} #{age} ]]> ``` ### fast quick building fast quick building is consists of 'and' and 'or'. These are two rules used to replace the simple 'if' tag and the simple 'foreach' tag. The following statement concatenates SQL when the parameter is not null ```xml ``` quick rule writing, where ':age' is the attribute name. ```xml ``` For example, 'foreach' : ```xml ``` quick rule writing, where ':list' is the collection attribute name. ```xml ``` If there are multiple simple conditions, fast writing can greatly reduce Mapper's workload. ### Paging query HasorDB's paging capability is supported only at the 'LambdaTemplate', 'BaseMapper', and 'Mapper DAO' levels. The following are different ways of using: Use 'LambdaTemplate' for paging queries ```java DataSource dataSource = DsUtils.dsMySql(); LambdaTemplate lambdaTemplate = new LambdaTemplate(dataSource); lambdaTemplate.loadSQL("CreateDB.sql"); // Build a paging object with 3 pieces of data per page (default first page is 0) Page pageInfo = new PageObject(); pageInfo.setPageSize(3); // paging query data List pageData1 = lambdaTemplate.lambdaQuery(TestUser.class) .usePage(pageInfo) .queryForList(); // query next page pageInfo.nextPage(); List pageData2 = lambdaTemplate.lambdaQuery(TestUser.class) .usePage(pageInfo) .queryForList(); ``` Use interface 'BaseMapper' for paging queries ```java DataSource dataSource = DsUtils.dsMySql(); DalSession session = new DalSession(dataSource); BaseMapper baseMapper = session.createBaseMapper(TestUser.class); baseMapper.template().loadSQL("CreateDB.sql"); // Build a paging object with 3 pieces of data per page (default first page is 0) Page pageInfo = new PageObject(); pageInfo.setPageSize(3); // paging query data PageResult pageData1 = baseMapper.queryByPage(pageInfo); // query next page pageInfo.nextPage(); PageResult pageData2 = baseMapper.queryByPage(pageInfo); ``` To query queries in Mapper files in pages, simply add a Page parameter to the DAO interface method. ```java @RefMapper("/mapper/quick_page3/TestUserMapper.xml") public interface TestUserDAO extends BaseMapper { // You can directly return the result of paged data public List queryByAge( @Param("beginAge") int beginAge, @Param("endAge") int endAge, Page pageInfo); // You can also return paging results with paging information public PageResult queryByAge2( @Param("beginAge") int beginAge, @Param("endAge") int endAge, Page pageInfo); } ``` ```java // Building paging conditions Page pageInfo = new PageObject(); pageInfo.setPageSize(3); List data1 = userDAO.queryByAge(25, 100, pageInfo); PageResult page1 = userDAO.queryByAge2(25, 100, pageInfo); pageInfo.nextPage(); List data2 = userDAO.queryByAge(25, 100, pageInfo); PageResult page2 = userDAO.queryByAge2(25, 100, pageInfo); ``` ### using transaction HasorDB provides three ways to use transactions: - ** using API **, by calling the 'TransactionManager' interface to achieve transaction control. - ** Template **, through the 'TransactionTemplate' interface to achieve transaction control. - ** Annotated ** annotated Transaction control based on '@Transaction' (dev ing...) ### transaction using API Start and submit a transaction, for example: ```java {4,8} DataSource dataSource = DsUtils.dsMySql(); TransactionManager manager = DataSourceManager.getManager(dataSource); TransactionStatus tranA = manager.begin(); ... manager.commit(tranA); ``` Or use shortcuts ```java {4,8} DataSource dataSource = DsUtils.dsMySql(); TransactionManager manager = DataSourceManager.getManager(dataSource); manager.begin(); ... manager.commit(); //commit last trans ``` Start and submit multiple transactions, such as: ```java DataSource dataSource = DsUtils.dsMySql(); TransactionManager manager = DataSourceManager.getManager(dataSource); TransactionStatus tranA = manager.begin(); TransactionStatus tranB = manager.begin(); TransactionStatus tranC = manager.begin(); ... manager.commit(tranC); manager.commit(tranB); manager.commit(tranA); ``` The 'begin' method allows you to set the transaction propagation ** and the isolation level ** ```java TransactionStatus tranA = manager.begin( Propagation.REQUIRES_NEW, // transaction propagation is same as Spring TX Isolation.READ_COMMITTED // isolation level ); ``` ### Template transaction Typically, transactions follow the following logic: ```java {2,6,8} try { manager.begin(behavior, level); ... manager.commit(); } catch (Throwable e) { manager.rollBack(); throw e; } ``` Template transactions follow this general logic to make a more general API call. The following code is the implementation logic of the template transaction class: ```java {5,9,14} title="类:net.hasor.db.transaction.support.TransactionTemplateManager" public T execute(TransactionCallback callBack, Propagation behavior, Isolation level) throws Throwable { TransactionStatus tranStatus = null; try { tranStatus = this.transactionManager.begin(behavior, level); return callBack.doTransaction(tranStatus); } catch (Throwable e) { if (tranStatus != null) { tranStatus.setRollback(); } throw e; } finally { if (tranStatus != null && !tranStatus.isCompleted()) { this.transactionManager.commit(tranStatus); } } } ``` The way to use a template transaction is: ```java Object result = template.execute(new TransactionCallback() { @Override public Object doTransaction(TransactionStatus tranStatus) { ... return null; } }); // Using the Java8 Lambda syntax can be simplified as follows Object result = template.execute(tranStatus -> { return ...; }); ``` Throwing an exception in a transaction template causes the transaction to roll back, while the exception continues to be thrown up: ```java {4} try { Object result = template.execute(new TransactionCallback() { public Object doTransaction(TransactionStatus tranStatus) { throw new Exception("..."); } }); } catch (Throwable e) { ... run here } ``` You can also set the transaction state to 'rollBack' or 'readOnly' to cause rollBack ```java {3,5} Object result = template.execute(new TransactionCallback() { public Object doTransaction(TransactionStatus tranStatus) { tranStatus.setReadOnly(); // 或 tranStatus.setRollback(); return ...; } }); ``` Not return a value template, need to use ` TransactionCallbackWithoutResult ` interface. Specific usage is as follows: ```java template.execute((TransactionCallbackWithoutResult) tranStatus -> { ... }); ```