Home

Awesome

sqltoy-orm 快速上手项目

学习步骤

1. 配置pom引入sqltoy的依赖

<dependency>
	<groupId>com.sagframe</groupId>
	<artifactId>sagacity-sqltoy-spring-starter</artifactId>
	<!-- jdk17+ /springboot3.x 请使用5.6.22 版本 -->
	<version>5.6.22.jre8</version>
</dependency>

<!-- 
注意注意: 配置连接池依赖

1、druid连接池
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid-spring-boot-starter</artifactId>
   <version>1.2.23</version>
</dependency>

2、springboot自带的hikari连接池需要额外增加依赖
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jdbc</artifactId>
	<version>2.7.18</version>
</dependency>
-->

2. 配置正确pom build避免sql文件无法编译到classes下面

<resources>
	<resource>
		<directory>src/main/java</directory>
		<excludes>
			<exclude>**/*.java</exclude>
		</excludes>
		<includes>
			<include>**/*.xml</include>
		</includes>
	</resource>
	<resource>
		<directory>src/main/resources</directory>
		<includes>
			<include>**/*.xml</include>
			<include>**/*.properties</include>
			<include>**/*.yml</include>
			<include>**/*.sql</include>
			<include>**/*.jpg</include>
            <include>**/*.key</include>
		</includes>
	</resource>
</resources>
<testResources>
	<testResource>
		<directory>src/test/java</directory>
		<excludes>
			<exclude>**/*.java</exclude>
		</excludes>
		<includes>
			<include>**/*.xml</include>
		</includes>
	</testResource>
	<testResource>
		<directory>src/test/resources</directory>
		<includes>
			<include>**/*.xml</include>
			<include>**/*.properties</include>
			<include>**/*.yml</include>
			<include>**/*.sql</include>
            <include>**/*.key</include>
		</includes>
	</testResource>
</testResources>

3. 配置application.yml,注意阅读配置上的备注

#完整路径:spring.sqltoy
spring:
   sqltoy:
        # 多个路径用逗号分隔(这里要注意是路径,sqltoy会自动向下寻找以sql.xml结尾的文件,不要写成classpath:com/**/*.sql.xml)
        sqlResourcesDir: classpath:com/sqltoy/quickstart
        # 默认值为classpath:sqltoy-translate.xml,一致则可以不用设置
        translateConfig: classpath:sqltoy-translate.xml
		# 默认开启跨数据库函数自动适配(如oracle的nvl,当数据库切到mysql时会自动替换成ifnull)
        #functionConverts: default
        # 默认为false,debug模式将打印执行sql,并自动检测sql文件更新并重新加载
        debug: true
        # 提供统一字段:createBy createTime updateBy updateTime 等字段补漏性(为空时)赋值(可选配置)
        unifyFieldsHandler: com.sqltoy.plugins.SqlToyUnifyFieldsHandler
        # sql执行超过多长时间则进行日志输出,用于监控哪些慢sql(可选配置:默认30秒)
        printSqlTimeoutMillis: 300000
        # 数据库保留字兼容处理(原则上不要使用数据库保留字,多个用逗号分隔)
        #reservedWords: maxvalue,minvalue
#完整路径:spring.sqltoy
spring:
   sqltoy:
        # 多个路径用逗号分隔(注意这里填路径、路径!会自动相信寻找)
        sqlResourcesDir: classpath:com/sqltoy/quickstart
# sqltoy config
spring.sqltoy.sqlResourcesDir=classpath:com/sqltoy/quickstart
# 默认配置:classpath:sqltoy-translate.xml;classpath:translates,可以多个.trans.xml 放于classpath:translates目录下面
spring.sqltoy.translateConfig=classpath:sqltoy-translate.xml
# 默认关闭函数替换
#spring.sqltoy.functionConverts=default
# 是否开启debug模式,在开发阶段建议为true,会打印sql
spring.sqltoy.debug=true
#项目中用到的数据库保留字定义,这里是举例,正常情况下不用定义
#spring.sqltoy.reservedWords=status,sex_type
# 设置获取数据源的策略实现类,只在多数据源场景下需要设置,DefaultDataSourceSelector是默认实现
#dataSourceSelector: org.sagacity.sqltoy.plugins.datasource.impl.DefaultDataSourceSelector
#spring.sqltoy.defaultDataSource=dataSource
spring.sqltoy.unifyFieldsHandler=com.sqltoy.plugins.SqlToyUnifyFieldsHandler
#spring.sqltoy.printSqlTimeoutMillis=200000

4. 编写springboot 主程序,注意@ComponentScan配置

package com.sqltoy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
 * 
 * @project sqltoy-quickstart
 * @description quickstart 主程序入口
 * @author zhongxuchen 
 * @version v1.0, Date:2020年7月17日
 * @modify 2020年7月17日,修改说明
 */
@SpringBootApplication
@ComponentScan(basePackages = { "com.sqltoy.config", "com.sqltoy.quickstart" })
@EnableTransactionManagement
public class SqlToyApplication {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SpringApplication.run(SqlToyApplication.class, args);
	}
}

5. 初始化数据库

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = SqlToyApplication.class)
public class InitDataBaseTest {

	@Autowired
	private InitDBService initDBService;

	@Test
	public void testInitDB() {
		String dbSqlFile = "classpath:mock/quickstart_init.sql";
		System.err.println("开始执行数据库初始化!");
		initDBService.initDatabase(dbSqlFile);
	}
}

6. 利用quickvo生产VO(或POJO)

#############  db config ####################
jdbc.driver_class=com.mysql.cj.jdbc.Driver
# url characterEncoding=utf-8 param is need
jdbc.url=jdbc:mysql://192.168.56.109:3306/quickstart?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false
# mysql schema=dbname,oracle schema=username
jdbc.schema=quickstart
jdbc.username=quickstart
jdbc.password=quickstart
<!-- db配置文件 -->
<property file="db.properties" />
<property name="project.version" value="1.0.0" />
<property name="project.name" value="sqltoy-quickstart" />
<property name="project.package" value="com.sqltoy" />
<property name="include.schema" value="false" />
<!--set method 是否支持返回对象自身(默认是false),即: public VO setName(String name){this.name=name;return this;} -->
<property name="field.support.linked.set" value="true" />
<!-- 是否在抽象类中生成SelectFieldImpl内部类,默认值为false	-->
<property name="generate.selectFields.class" value="true" />
<!-- schema 对照关系:mysql 对应  db 名称; oracle 对应 用户名称;   -->
<!-- 注意:当在多schema或tablespace场景下,会出现一个表中出现重复字段,是因为schema和catalog 配置不正确,没有完成隔离   -->
<datasource name="quickstart" url="${db.url}" driver="${db.driver_class}" 
		schema="${db.schema}" catalog="${db.schema}" username="${db.username}" password="${db.password}" />
<tasks dist="../../src/main/java" encoding="UTF-8">
	<!-- include 是表名匹配的正则表达式  -->
	<task active="true" author="zhongxuchen" include="^SQLTOY_\w+" datasource="quickstart" swagger-model="false">
		<!-- substr 表示截取表名的前缀部分(一般表会按模块增加前缀),如不截取则substr="" name="#{subName}VO" subName是约定词,VO这两个字符可以随意改变  -->
		<entity package="${project.package}.quickvo.vo" substr="Sqltoy" name="#{subName}VO" />
	</task>
</tasks>
java -cp ./libs/* org.sagacity.quickvo.QuickVOStart quickvo.xml
java -cp ./libs/\* org.sagacity.quickvo.QuickVOStart ./quickvo.xml

源码导航

疑问解答

为什么要将*.sql.xml 放在java路径下?

为什么缓存不用redis?

为什么quickvo任务不是一个,而是按模块分多个任务

如何分VO和POJO

如何分库分表

为什么dao不采用mybatis plus的接口模式?

@Service("organInfoService")
public class OrganInfoServiceImpl implements OrganInfoService {
    //sqltoyLazyDao 就可以代替接口式的dao
	@Autowired
	SqlToyLazyDao sqlToyLazyDao;

	@Transactional
	public void saveOrganInfo(OrganInfoVO organInfoVO) {
		// 先保存机构
		sqlToyLazyDao.saveOrUpdate(organInfoVO);
		// 设置树形表的节点路径等字段值,便于统一树形查询
		// id字段根据vo找表的主键会自动匹配上,其它的NODE_ROUTE\NODE_LEVEL\IS_LEAF 为标准命名无需额外设置
		//idField 如果是主键则无需设置
		sqlToyLazyDao.wrapTreeTableRoute(new TreeTableModel(organInfoVO).pidField("organPid"));
	}
}

如下:实体类又有何不妥呢!清晰又可以针对一些特殊情况自己完善一些小处理,mybatis那种接口通过aop方式谈不上什么酷和高技术,不要被带到沟里去了,清晰、可维护、好拓展才是正道!

@Repository("staffInfoDao")
public class StaffInfoDao extends SqlToyDaoSupport {
	/**
	 * @TODO 提供一个分页并动态设置缓存翻译的演示
	 * @param pageModel
	 * @param staffInfoVO
	 * @return
	 */
	public Page<StaffInfoVO> findStaff(Page<StaffInfoVO> pageModel, StaffInfoVO staffInfoVO) {
		// sql可以直接在代码中编写,复杂sql建议在xml中定义
		// 单表entity查询场景下sql字段可以写成java类的属性名称
		// 单表查询一般适用于接口内部查询
		String sql = "#[staffName like :staffName]#[and createTime>=:beginDate]#[and createTime<=:endDate]";
		return findPageEntity(pageModel,StaffInfoVO.class, EntityQuery.create().where(sql).values(staffInfoVO)
				// 字典缓存必须要设置cacheType
				// 单表对象查询需设置keyColumn构成select keyColumn as column模式
				.translates(new Translate("dictKeyName").setColumn("sexTypeName").setCacheType("SEX_TYPE")
						.setKeyColumn("sexType"))
				.translates(new Translate("organIdName").setColumn("organName").setKeyColumn("organId")));
	}

多数据源怎么弄?

spring.sqltoy.defaultDataSource=dataSourceName
	 @Bean(name = "sqlToySkylineDao")
    public SqlToyLazyDao sqlToySkylineDao(@Qualifier("dataSourceSkyline") DataSource dataSource){
        SqlToyLazyDaoImpl dao = new SqlToyLazyDaoImpl();
        dao.setDataSource(dataSource);
        return dao;
    }

    @Bean(name = "sqlToyLazyDao")
    public SqlToyLazyDao sqlToyLazyDao(@Qualifier("dataSource") DataSource dataSource) {
        SqlToyLazyDaoImpl dao = new SqlToyLazyDaoImpl();
        dao.setDataSource(dataSource);
        return dao;
    }
sqlToyLazyDao.save().dataSource(dataSource).saveMode(SaveMode.IGNORE).many(entities);
sqlToyLazyDao.query().sql("qstart_fastPage").dataSource(dataSource).entity(staffVO).findPage(pageModel);

我想通过包路径来实现不同数据库访问

public class DefaultDataSourceSelector implements DataSourceSelector {

	@Override
	public DataSource getDataSource(ApplicationContext applicationContext, DataSource pointDataSouce,
			String sqlDataSourceName, DataSource injectDataSource, DataSource defaultDataSource) {
		// 第一优先:直接指定的数据源不为空
		if (pointDataSouce != null) {
			return pointDataSouce;
		}
		DataSource result = null;
		// 第二优先:sql中指定的数据源<sql id="xxx" datasource="xxxxDataSource">
		if (StringUtil.isNotBlank(sqlDataSourceName)) {
			result = getDataSourceBean(applicationContext, sqlDataSourceName);
		}
		// 第三优先:dao中autowired注入的数据源
		if (result == null) {
			result = injectDataSource;
		}
		// 第四优先:sqltoy 统一设置的默认数据源
		if (result == null) {
			result = defaultDataSource;
		}
		// 如果项目中只定义了唯一的数据源,则直接使用
		if (result == null) {
			Map<String, DataSource> dataSources = applicationContext.getBeansOfType(DataSource.class);
			// 只有一个dataSource,直接使用
			if (dataSources.size() == 1) {
				result = dataSources.values().iterator().next();
			}
		}
		return result;
	}
}

sqltoy传参支持map吗?

    /**
	 * @todo 通过对象传参数,简化paramName[],paramValue[] 模式传参
	 * @param <T>
	 * @param sqlOrNamedSql 可以是具体sql也可以是对应xml中的sqlId
	 * @param entity        通过对象传参数,并按对象类型返回结果
	 * @return
	 */
	public <T extends Serializable> List<T> findBySql(final String sqlOrNamedSql, final T entity);
	
	/**
	 * @todo 通过给定sql、sql中的参数名、参数的数值以及返回结果的对象类型进行条件查询
	 */
	public <T> List<T> findBySql(final String sqlOrSqlId, final String[] paramsNamed, final Object[] paramsValue,
			final Class<T> voClass);
	/**
	 * @todo 通过map传参
	 */
    public <T> List<T> findBySql(final String sqlOrSqlId, final Map<String, Object> paramsMap, final Class<T> voClass);

sqltoy必须返回VO吗?

    /**
	 * @todo 通过给定sql、sql中的参数、参数的数值以及返回结果的对象类型进行条件查询
	 * @param sqlOrSqlId
	 * @param paramsNamed 如果sql是select * from table where xxx=?
	 *                    问号传参模式,paramNamed设置为null
	 * @param paramsValue 对应Named参数的值
	 * @param voClass     返回结果List中的对象类型(可以是VO、null:表示返回List<List>;HashMap.class,Array.class 返回List<Object[])
	 * @return
	 */
	public <T> List<T> findBySql(final String sqlOrSqlId, final String[] paramsNamed, final Object[] paramsValue,
			final Class<T> voClass);

sqltoy 的sql必须写在xml中吗?

public <T> List<T> findBySql(final String sqlOrSqlId, final String[] paramsNamed, final Object[] paramsValue,
			final Class<T> voClass);

还有??