Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

obase/java

Repository files navigation

Obase系列是一套基于"spring+mysql+redis"的Java后端开发技术, 可以说是笔者多年开发经验沉湎.

  • obase-webc: 基于COC的MVC, 无web.xml启动, 很好支持前后端分离. 用户基于原生HttpServlet API开发.
  • obase-mysql: 一套使用Annotation+ASM实现hibernate + mybatis优势功能的ORM框架. 自动封装, 一条SQL多种用途: 单值查询, 区间查询, 分页查询(支持字段排序), 其实ORM也可以很轻量.
  • obase-jedis: 谈不上框架, 就是对JedisPool资源获取释放的封装.
  • obase-config: 实现PropertySourcePlaceholderConfiguer的功能, 并支持Redis, Mysql动态配置定期更新功能. 另外, 还支持配置项的AES128加密, 避免你的配置项明文存放.
  • obase-test: 嵌入式Tomcat8 + Junit4, 支持环境变量的动态注入. 可以容易测试https和spring bean.
  • obase-loader: 加密字节码发布时用的classloader. 对于商业代码比较实用!
新版本,新气象,obase经过0.x版本过渡后已经发行正式版本1.2.0. 
- obase-web与spring-boot的设计理念无缝对接, 
- obase-mysql支持动态sql, 完美集成hibernate与mybatis的优势! 
新源码在公司内部多个项目运行稳定, 相关文档正在整理补充!

开源obase扎根"spring+mysql+redis", 框架思路可以扩展到其他... 如memcache, postsql. 在此就不做讨论了.

obase-webc

  • obase-webc最新版本
<dependency>
	<groupId>com.github.obase</groupId>
	<artifactId>obase-webc</artifactId>
	<version>1.2.0</version>
</dependency>

obase-webc是什么?

obase-webc是基于servlet 3.0+的AsyncContext实现的无web.xml开发模式.在Filter层面实现了Spring MVC的功能, 并移除了HandlerMapping与ViewResolver, 以COC简化Spring MVC的烦人配置. 优点有什么? 试下呗.

obaes-webc怎么用?

obase-webc的使用方法:

源码maven目录结构参考: https://github.com/obase/java/tree/master/obase-demo, 用户需要继承obase-parent

<parent>
	<groupId>com.github.obase</groupId>
	<artifactId>obase-parent</artifactId>
	<version>1.1.0</version>
</parent>

里面定义了spring, servlet, jsp的核心版本.

  • 第1步: 创建/META-INF/webc.xml
<?xml version="1.0" encoding="UTF-8"?>
<webc xmlns="http://obase.github.io/schema/webc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://obase.github.io/schema/webc
	https://obase.github.io/schema/obase-webc-1.0.xsd">
</webc>

/WEB-INF/webc.xml或/META-INF/webc.xml是obase-webc启用"阀门".

  • 第2步: 创建/META-INF/servletContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context.xsd">
	<context:component-scan base-package="com.github.obase.demo.controller" />
</beans>
  • 第3步: 创建Controller
package com.github.obase.demo.controller;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import com.github.obase.webc.Kits;
import com.github.obase.webc.annotation.ServletMethod;
@Controller
public class TestController {
	@ServletMethod
	public void hello(HttpServletRequest request, HttpServletResponse response) throws IOException {
		String name = Kits.readParam(request, "name");
		Kits.writeSuccessMessage(response, "hello " + name);
	}
}
  • 第4步: 创建HttpServer
package com.github.obase.test;
public class HttpServer {
	public static void main(String[] args) {
		EmbedTomcat.start();
	}
}

启动HttpServer, 浏览器输入"http://localhost/test/hello?name=jason.he"

{"errno":0,"data":"hello jason.he"}

obase-webc与spring-boot整合

DEMO: https://github.com/obase/java/tree/master/obase-spring-boot
  • maven依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.github.obase</groupId>
		<artifactId>obase-parent</artifactId>
		<version>1.2.0</version>
	</parent>
	<artifactId>obase-spring-boot</artifactId>
	<packaging>war</packaging>
	<properties>
		<spring.boot.version>1.5.9.RELEASE</spring.boot.version>
		<spring.version>4.3.10.RELEASE</spring.version>
		<jackson.version>2.9.0</jackson.version>
		<java.version>1.8</java.version>
		<obase.version>1.2.0-SNAPSHOT</obase.version>
	</properties>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-dependencies</artifactId>
				<version>${spring.boot.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>javax.servlet.jsp-api</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.github.obase</groupId>
			<artifactId>obase-webc</artifactId>
			<version>${obase.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.github.obase</groupId>
			<artifactId>obase-test</artifactId>
			<scope>test</scope>
			<version>${obase.version}</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>${spring.boot.version}</version>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-surefire-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

其中properties的值确保obase-webc与spring-boot使用相同版本依赖.

  • java代码

//注意org.springframework.boot.web.servlet.ServletContextInitializer
//不是javax.servlet.ServletContainerInitializer
package demo.test.main;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import com.github.obase.webc.WebcServletContainerInitializer;
@SpringBootApplication
public class Main extends WebcServletContainerInitializer implements ServletContextInitializer {
	public static void main(String[] args) {
		SpringApplication.run(Main.class, args);
	}
}

执行mvn clean package命令即可得到执行的war.

obase-webc的初衷: 抛弃spring-webmvc, 在spring-web + Servlet 3.0+ 基础结合COC打造一款全新的MVC.

  • 前后端分离, 实现无web.xml启动, 把src/main/webapp目录完全交给前端团队.
  • 统一URL映射, 基于COC的映射规则.
  • 可简可烦, 简单时创建一个webc.xml即可使用, 不用再配置web.xml, 也不用再配置各种框架servlet; 复杂时可以细粒度控制API访问策略, 接管Spring Security的功能.
  • 与servlet共存, 这样就能与spring-mvc无缝整合(历史遗留原因). --- 基于Filter技术实现.
  • 支持动态session cookie校验. --- 启用后cookie自带时间戳与hash指纹.
  • 支持类似restful的API, 支持UI与API共用相同的Controller. --- @Controller + @ServletMethod
  • 支持微服务框架. --- @Service + @InvokerService
  • 支持多机部署+分布式会话.
  • 没有反射损耗. reflect太out了, 基于ASM + ServletMethodFilter 自动组装拦截代码到@ServletMethod方法.
  • 保持最小侵入. 该点最关键, 也是最重要. 使用者只需知道@InvokerService, @ServletMethod, SerlvetMethodFilter, ServletMethodProcssor几个注解或API, 其他还是HttpServlet API, 或者Spring API.

后面会具体一一介绍.

obase-jedis

  • obase-jedis 最新版本
<dependency>
	<groupId>com.github.obase</groupId>
	<artifactId>obase-jedis</artifactId>
	<version>1.2.0</version>
</dependen

obase-test

  • obase-test 最新版本
<dependency>
	<groupId>com.github.obase</groupId>
	<artifactId>obase-test</artifactId>
	<version>1.2.0</version>
</dependen

obase-test是什么?

封装了embedded tomcat 8与junit4, 简单即可实现https的测试, 以及Spring Context上下文单元测试. 为什么不用Jetty9? 用过你就知道jetty9 对于Servlet 3.0+的支持有多烦!

obase-config

  • obase-config 最新版本
<dependency>
	<groupId>com.github.obase</groupId>
	<artifactId>obase-config</artifactId>
	<version>1.2.0</version>
</dependen

obase-config是什么?

基于Spring, 实现PropertySourceConfigurer的功能, 更多地... 支持redis与mysql的动态配置获取与定时更新, 还有... 加密配置项, 这个对于敏感数据来说是一种简洁的处理方式.

obase-loader

  • obase-loader 最新版本
<dependency>
	<groupId>com.github.obase</groupId>
	<artifactId>obase-loader</artifactId>
	<version>1.2.0</version>
</dependen

obase-loader是什么?

你的jar需要加密发布么? obase-loader基于spring context的classloader机制, 实现加载时解密字节码功能.

obase-mysql

  • obase-mysql最新版本
<dependency>
	<groupId>com.github.obase</groupId>
	<artifactId>obase-mysql</artifactId>
	<version>1.2.0</version>
</dependency>

obase-mysql是什么?

顾名思议, obase-mysql是针对mysql的一个jdbc封装工具.在实际项目使用了几年的hibernate, mybatis, spring-jdbc后发现每种框架各有特点,同时存在一些不尽人意的地方:

关于Hibernate:

  • Hibernate封装Entity(配置hibernate.hbm2ddl.auto还能自动管理表结构),单表操作不需写任何SQL,这点很爽. 但多表操作呢? Hibernate的HQL太致命,不支持子查询,外连接(left join, right join)查询必须配置@OneToMany, @ManyToMany 等关联注解. 很多同学会说Hibernate支持Native SQL呀. 嗯,基于本地SQL接口可以写任何SQL,但是要求开发自己去封装Object[]结果. 如果这样的情景多了, 为什么不倒回去用Spring-jdbc的RowMapper呢? 或许你又会抱怨, 哪每张表又要去写一些雷同的CRUD SQL了!!!
  • Hibernate的HQL经过antlr语法解析成ADT(抽象语法树),最后结合Dialect配置转成具体数据库的SQL语法, 例如很多喜欢的分页查询, 在mysql转成limit clause, 在oracle则配合rownum进行过滤. 这中间经过2层转换, 性能么? 一直是很多开发抱怨的焦点.
  • Hibernate提供了一级缓存,甚至你可以配置二级存减少数据库查询频率,提高数据查询性能.某种层面,这种cache管理的高超技巧实在令人赏心悦目,叹为观止. 但是...但是...对于大多数据的互联网应用为了HA(高可用)和LB(负载均衡), 都会采用多机部署模式. 在这种情况下, 各色单机的缓存绝对能让你发疯再发懵, 著名的CAP理论得到最切实的验证. 最后,为了绕过缓存,每次操作完后必须调用flush(), clear()...何必呢? 我用mybatis, spring-jdbc不是更省事么? 但是...单表操作的需求又"蛋疼"了.
  • Hibernate总体而言,有3个使用层次, 学习难度逐层翻倍:
    1. 表映射, 包括单字段映射,多字段映射. 大多数开发都停留在这个阶段.
    2. 表关联, 包括一对一关联,一对多关联,多对多关联. 关联对查询性能的影响很大, 优化策略就是建议外键部分尽可能用lazy,少用eager,但要十分小心"蛋疼"的LazyInitializationException. 另外, Hibernate官方特别强调关联深度问题,建议不要超过3层. 还有, 推荐用小表作为主表关联大表...等等. 哪些没对Hibernate进行系统研究的开发, 我只能建议如无必要,别在你的项目中使用表关联.
    3. 表继承, Hibernate的继承策略有3种实现策略: 单表继承策略(table per class), 外键Joined策略(table per subclass), 和标识字段策略(table per class). 选择不同策略必须谨慎, 影响最致命的不是程序, 而是表结构与数据存储. 毕竟代码的东西大不了重写, 但数据乱了, 你还能"蛋定"地轻描淡写说一声: "大不了重新生成数据"么? 果真英雄!

以上是我从2009年开始使用Hibernate以来的一些真实感受! 简单总结: 只用hibernate的表映射, 少量使用表关联,而且层级<2. 打死不用表继承...另外,高并发性能的查询接口使用Native SQL. 必要时使用procedure.

关于Mybatis(ibatis):

  • mybatis的核心就是SqlMap, 够简单, 无需赘述, 如果mybatis都看不懂呢?
  • mybatis的动态SQL标签, 看起来是功能够强的! 对于动态拼接,只能说是"山与水的关系", 仁者乐山, 智者乐水. 动态特性满足了哪些喜欢拼接SQL的开发心理, 特别是使用$参数的静态替换. 只要存在动态拼接参数, 就有SQL注入的风险!
  • mybatis支持SQL参数与结果的自动映射,这点比起hibenrate灵活很多. 但这种实现是基于反射的,直接的结果就是导致mybatis比hibernate native sql没有太多的性能优势.

以上是我这几年使用mybatis以来的一些体会, 从某种层面来说, mybatis能够符合大多数开发需求! 难怪淘宝系的基础技术中就有ibatis. 但是mybatis没有批量操作的接口, 以及不能像hibernate哪样自动管理数据表结构, 甚至分页也需要借助第三方插件...不免有些失落.

很多项目同时应用了hibernate与mybatis,取长补短,本来思路很不错! 但是都忽略了一个活生生的事实: hibernate与mybatis与spring事务的集成接口不同! 换言之, 项目里面的代码, 要么用hibernate, 要么用mybatis. 混用二者, 事务会成很大的问题.

洋洋洒洒扯了这么多, 大家应该明白spring-mysqlclient的设计初衷了吧. 说白了就是综合了hibernate与mybatis的好用特性, 同时使用ASM字节码技术替代动态反射, 提升查询过程的性能.

obase-mysql有哪些功能

  • mysqlclient开启updateTable特性, 允许自动根据@Table类更新数据表结构. 但仅限于"增加"操作. 具体规则:

    1. 如果表不存在, 则自动创建表, 以及定义主键, 外键, 索引.

    2. 如果表存在, 则检查表结构:

      1. 比较字段, 如果存在同名字段, 则不再修改.
      2. 比较主键, 如果存在主键则不再修改. 但会检查主键字段是否相同, 并显示相关警告信息.
      3. 比较外键, 如果存在同名外名, 则不再修改.
      4. 比较索引, 如果存在同名索引, 则不再修改.

      详细过程, 可以查看 com.github.risedragon.mysql.jdbc.SqlDdlKit.processUpdateTable() 方法.

  • mysqlclient提供单表记录的insert, update, replace, merge, delete, batchInsert, batchUpdate, batchReplace, batchMerge, batchDelete, select, select2, selectFirst, selectRange, selectPage操作. 这些操作只需配置@Table, @Column注解即可, 不用写任何SQL. 详细用法, 可以参见<快速上手>.

  • mysqlclient提供命名SQL支持, 并对参数与结果的提取自动封装. 除了预定义的SqlType与JavaType类预定的scalar类型, 用户可以基于ActionMeta接口定制实现, 通过 JdbcAction.markSqlType() 注册到框架, 最常见就是支持复合参数IN(:list). 详细用法, 可以参见<快速上手>.

  • mysqlclient提供SQL的常见查询接口: query, queryFist, queryRange, queryPage. 其中分页接口Page, 还提供字段排序功能. 详细用法, 可以参见<快速上手>.

  • mysqlclient提供SQL的常见操作接口: execute, batchExecute.

  • 另外, mysqlclient提供独立事务管理接口MysqlClientExt满足不需要Spring的PlatformTransactionManager管理事务的应用, 完全编程细粒度控制事务的提交与回滚. 详细用法, 可以参见<快速上手>

obase-mysql快速上手

  • 定义实体

使用@Table注解

 @OptimisticLock(column = "version")
public abstract class Base {
	@Column(key = true, autoIncrement = true, comment = "自增主键")
	Long id;
	@Column(length = 16)
	String createBy;
	@Column
	Date createTime;
	@Column(length = 16)
	String modifyBy;
	@Column
	Date modifyTime;
	@Column
	Long version;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getCreateBy() {
		return createBy;
	}
	public void setCreateBy(String createBy) {
		this.createBy = createBy;
	}
	public Date getCreateTime() {
		return createTime;
	}
	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}
	public String getModifyBy() {
		return modifyBy;
	}
	public void setModifyBy(String modifyBy) {
		this.modifyBy = modifyBy;
	}
	public Date getModifyTime() {
		return modifyTime;
	}
	public void setModifyTime(Date modifyTime) {
		this.modifyTime = modifyTime;
	}
	public Long getVersion() {
		return version;
	}
	public void setVersion(Long version) {
		this.version = version;
	}
}
@Table(engine=Engine.InnoDB, characterSet="UTF8")
public class Employee extends Base {
	@Column(length = 64, comment = "工号")
	String cardNo;
	@Column(length = 16, comment = "类型")
	String type;
	@Column(length = 16, comment = "姓名")
	String name;
	@Column(length = 8, comment = "性别")
	String gender;
	@Column(length = 16, comment = "部门")
	String groupName;
	@Column(length = 16, comment = "手机号码")
	String phone;
	@Column(length = 18, comment = "身份证号码", unique = true)
	String sid;
	@Column(length = 18, comment = "护照号码", unique = true)
	String passportNo;
	@Column(length = 18, comment = "护照汉字拼音")
	String passportAbbr;
	@Column(length = 8, comment = "虚拟房间号")
	String room;
	@Column(comment = "带薪旅游假期")
	Date paidHoliday;
	@Column(length = 8, defaultValue = "年假", comment = "抵扣假期")
	String holidayType;
	@Column(length = 18, comment = "办公地点")
	String officeLocation;
	@Column
	BigDecimal other;
	public String getCardNo() {
		return cardNo;
	}
	public void setCardNo(String cardNo) {
		this.cardNo = cardNo;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public String getGroupName() {
		return groupName;
	}
	public void setGroupName(String groupName) {
		this.groupName = groupName;
	}
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
	public String getSid() {
		return sid;
	}
	public void setSid(String sid) {
		this.sid = sid;
	}
	public String getPassportNo() {
		return passportNo;
	}
	public void setPassportNo(String passportNo) {
		this.passportNo = passportNo;
	}
	public String getPassportAbbr() {
		return passportAbbr;
	}
	public void setPassportAbbr(String passportAbbr) {
		this.passportAbbr = passportAbbr;
	}
	public String getRoom() {
		return room;
	}
	public void setRoom(String room) {
		this.room = room;
	}
	public Date getPaidHoliday() {
		return paidHoliday;
	}
	public void setPaidHoliday(Date paidHoliday) {
		this.paidHoliday = paidHoliday;
	}
	public String getHolidayType() {
		return holidayType;
	}
	public void setHolidayType(String holidayType) {
		this.holidayType = holidayType;
	}
	public String getOfficeLocation() {
		return officeLocation;
	}
	public void setOfficeLocation(String officeLocation) {
		this.officeLocation = officeLocation;
	}
	public Long getVersion() {
		return version;
	}
	public void setVersion(Long version) {
		this.version = version;
	}
	public BigDecimal getOther() {
		return other;
	}
	public void setOther(BigDecimal other) {
		this.other = other;
	}
	public String toString() {
		return JsonUtils.writeValueAsString(this);
	}
}

使用<table>标签

<?xml version="1.0" encoding="UTF-8"?>
<mysql>
 <table>com.yy.risedev.myweb.entity.Employee</table>
 ...
</mysql>
  • 定义持久与临时的JdbcAction

    JdbcAction接口实现SQL参数设置与结果提取的封装. mysqlclient基于ASM自动生成相关的代理类型.

    注意: @Table注解或

    标签定义的实体已经是个Meta, 无需再重复定义!

    使用@Meta注解

    @Meta
    public class EmpPart {
    	Long id;
    	Long version;
    	String cardNo;
    	String groupName;
    	public Long getId() {
    		return id;
    	}
    	public void setId(Long id) {
    		this.id = id;
    	}
    	public Long getVersion() {
    		return version;
    	}
    	public void setVersion(Long version) {
    		this.version = version;
    	}
    	public String getCardNo() {
    		return cardNo;
    	}
    	public void setCardNo(String cardNo) {
    		this.cardNo = cardNo;
    	}
    	public String getGroupName() {
    		return groupName;
    	}
    	public void setGroupName(String groupName) {
    		this.groupName = groupName;
    	}
    	public String toString() {
    		return JsonUtils.writeValueAsString(this);
    	}
    }

    使用<meta>标签

    <?xml version="1.0" encoding="UTF-8"?>
    <mysql>
     <table>com.yy.risedev.myweb.model.EmpPart</table>
     ...
    </mysql>
    • 定义sql 使用<sql>标签

    注意:namespace是可选的,一旦定义,使用SQL时必须带上,例如下述xml中为test.insertPartEmployee 完整schema定义

    <?xml version="1.0" encoding="UTF-8"?>
    <mysql namespace="test">
     <sql id="insertPartEmployee">
    	<![CDATA[INSERT INTO Employee (id,version,cardNo,groupName) VALUES(:id,:version,:cardNo,:groupName) ON DUPLICATE KEY UPDATE version=version+1, cardNo=:cardNo, groupName=:groupName]]>
     </sql>
     ...
    </mysql>
    • 在spring中配置mysqlclient

      容器管理事务的实现 MysqlClientPlatformTransactionImpl

      	<bean id="mysqlClient" class="com.github.risedragon.mysql.impl.MysqlClientPlatformTransactionImpl" init-method="init">
      	<property name="dataSource" ref="dataSource" />
      	<property name="packagesToScan" value="com.yy.risedev.myweb.entity,com.yy.risedev.myweb.model" />
      	<property name="configLocations" value="classpath:config/*.xml" />
      	<property name="showSql" value="true" />
      	<property name="updateTable" value="true" />
      </bean>
      

      编程管理事务的实现 MysqlClientConnectTransactionImpl

      	<bean id="mysqlClient" class="com.github.risedragon.mysql.impl.MysqlClientConnectTransactionImpl" init-method="init">
      	<property name="dataSource" ref="dataSource" />
      	<property name="packagesToScan" value="com.yy.risedev.myweb.entity,com.yy.risedev.myweb.model" />
      	<property name="configLocations" value="classpath:config/*.xml" />
      	<property name="showSql" value="true" />
      	<property name="updateTable" value="true" />
      </bean>
      

      各个属性说明:

    属性 功能 默认值
    dataSource 数据源引用,任何java.sql.DataSource实例
    packagesToScan 扫描@Table或@Meta类的起始包,多值用逗号分隔,例如"a.b.c,a.b.d"
    configLocations 加载sql xml的Spring Resource Pattern, 多值用逗号分隔,例如"classpath:a/b/c/*.xml,classpath:a/b/d/*.xml"
    showSql 显示操作的SQL. 建议测试环境打开,生产环境关闭 false, 默认关闭
    updateTable 是否更新表结构. 如果为true, 则根据@Table与@Column的定义更新表结构. 详细规则参见<mysqlclient开启updateTable特性>. false, 默认关闭此特性!
  • 在spring中支持容器事务

    基于注解@Transactional

    <bean id="transactionManager" class="com.github.risedragon.spring.transaction.DataSourceTransactionManager">
    	<property name="dataSource" ref="dataSource" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" />

    基于TransactionTemplate

    <bean id="transactionManager" class="com.github.risedragon.spring.transaction.DataSourceTransactionManager">
    	<property name="dataSource" ref="dataSource" />
    </bean>
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
    	<constructor-arg ref="transactionManager"/>
    </bean>
  • 实体操作: insert, insertIgnore, replace, update, merge, delete, select, select2, batchInsert, batchInsertIgnore, batchReplace, batchUpdate, batchMerge, batchDelete, selectFirst, selectRange, selectPage等

@Service
@Transactional
public class GenericService {
	@Autowired
	MysqlClient mysqlClient;
	public void insret() throws SQLException {
		Employee emp = new Employee();
		emp.setGroupName("测试部门");
		emp.setCardNo("135-137");
		Long id = mysqlClient.insert(emp, Long.class);
		System.out.println(id);
		throw new SQLException();
	}
	public void update() throws SQLException {
		Employee emp = mysqlClient.selectByKey(Employee.class, 3);
		emp.setPaidHoliday(new Date());
		System.out.println(mysqlClient.update(emp));
	}
	public void replace() throws SQLException {
		Employee emp = new Employee();
		emp.setId(4L);
		mysqlClient.select2(emp);
		emp.setCardNo("111-222-333");
		emp.setPaidHoliday(new Date());
		System.out.println(mysqlClient.replace(emp));
	}
	public void merge() throws SQLException {
		Employee emp = new Employee();
		emp.setCardNo("999-666-333");
		emp.setPaidHoliday(new Date());
		System.out.println(mysqlClient.merge(emp, BigDecimal.class));
	}
	public void delete() throws SQLException {
		Employee emp = mysqlClient.selectByKey(Employee.class, 5L);
		System.out.println(emp);
		System.out.println(mysqlClient.deleteByKey(Employee.class, 6L));
	}
	public void selectPage() throws SQLException {
		Page<Employee> page = new Page<>(2, 0, "id", true);
		mysqlClient.selectPage(Employee.class, page);
		System.out.format("total=%d,data=%s", page.getTotal(), page.getData());
	}
	public void showTables() throws SQLException {
		List<Object> list = mysqlClient.query("test.showTables", null, null);
		System.out.println(list);
	}
	public void selectBySql() throws SQLException {
		// List<EmpPart> list = mysqlClient.queryRange("test.selectPartEmployee", EmpPart.class, 0, 2, Arrays.asList(5, "%666%"));
		long start = System.currentTimeMillis();
		for (int i = 0; i < 100000; i++) {
			Page<EmpPart> page = new Page<>(0, 0, "id", true);
			mysqlClient.queryPage("test.selectPartEmployee", EmpPart.class, page, Arrays.asList(5, "%"));
		}
		long end = System.currentTimeMillis();
		System.out.println("used time:" + (end - start));
		// System.out.println(JsonUtils.writeValueAsString(page));
	}
	public void insertBySql() throws SQLException {
		long start = System.currentTimeMillis();
		int base = 1000;
		EmpPart[] array = new EmpPart[1000];
		for (int i = 0; i < 1000; i++) {
			EmpPart part = new EmpPart();
			part.setCardNo(String.format("000-001-%05d", i + 2000));
			part.setId(i * 1L + base);
			part.setGroupName("测试SQL分组");
			part.setVersion(null);
			array[i] = part;
		}
		Long[] result = mysqlClient.batchExecute("test.insertPartEmployee", array, Long.class);
		long end = System.currentTimeMillis();
		System.out.println("used time:" + (end - start));
		System.out.println(Arrays.asList(result));
	}
	public void executeCallback() throws SQLException {
		mysqlClient.callback(new ConnectionCallback<Void>() {
			@Override
			public Void doInConnection(Connection conn) throws SQLException {
				for (int i = 0; i < 10000 * 10; i++) {
					Statement stmt = conn.prepareStatement("show tables");
				}
				return null;
			}
		});
	}
	public void insertIgnore() throws SQLException {
		long start = System.currentTimeMillis();
		List<Employee> list = new LinkedList<Employee>();
		for (int i = 0; i < 10000; i++) {
			Employee emp = new Employee();
			emp.setId(i * 1L + 1);
			emp.setCardNo(String.format("000-001-%05d", i + 3000));
			emp.setGroupName("group " + i);
			emp.setOther(BigDecimal.valueOf(i));
			mysqlClient.merge(emp, Long.class);
		}
		// Long[] result = mysqlClient.batchInsertIgnore(list.toArray(), Long.class);
		long end = System.currentTimeMillis();
		System.out.println("used time:" + (end - start));
		// System.out.println(Arrays.toString(result));
	}
	public void selectRange() throws SQLException {
		List<Employee> list = mysqlClient.selectRange(Employee.class, 0, 1000);
		for (Employee item : list) {
			System.out.println(item);
		}
	}
}
  • SQL操作: query, queryFirst, queryRange, queryPage, execute, batchExecute

    <见上

obase-mysql 高级应用

  • 灵活的乐观锁定制

  • 结合JAVA继承体系,实现引擎数据操作的灵活性

  • 支持灵活多变的数据返回接口

obase-mysql 定制扩展

  • 扩展JdbcAction

    假设要对EmpPart自定义JdbcAction实现, 只需要按照命名规范$JdbcAction实现子类即可. 例如

 public class EmpPart$JdbcAction extends JdbcAction{
 ...
 }
通过AsmKit.newJdbcAction()就可以加载创建实例.
  • 扩展ActionMeta

    如果对某个字段类型要特别定制, 请实现ActionMeta, 并由JdbcAction.markSqlType()注册, 后面遇到该类型的字段后会自动调用该ActionMeta设置参数或提取结果. 例如集合参数的处理.

联系方式

开发者 联系方式
jasonhe jasonhe.hzw@foxmail.com, QQ:1255422783

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /