mysql异步查询 java_基于 mysql 异步驱动的非阻塞 Mybatis

虽然 spring5 也推出了 WebFlux 这一套异步技术栈,这种极大提升吞吐的玩法在 node 里玩的风生水起,但 java 世界里异步依旧不是主流,Vertx 倒是做了不少对异步的支持,但是其对于数据访问层的封装依旧还是挺精简的,传统的 javaer 还是受不了这种没有对象映射的工具库,于是我尝试将 Mybatis 移植到了异步驱动上,让数据访问层的工作变得更简单一些。给个例子:

@Sql(User.class)

public interface CommonMapper {

@Select(columns = "id,age,username")

@OrderBy("id desc")

@Page

@ModelConditions({

@ModelCondition(field = "username", criterion = Criterions.EQUAL),

@ModelCondition(field = "maxAge", column = "age", criterion = Criterions.LESS),

@ModelCondition(field = "minAge", column = "age", criterion = Criterions.GREATER)

})

void query(UserSearch userSearch, DataHandler> handler);

}

上面是 mapper 接口定义,方法的最后一个参数因为异步的原因所以变成了一个回调,不同的是有很多注解来表达 sql,看到这些注解应该不难猜出 sql 语句吧。如果不喜欢你当然可以继续使用 mapper.xml 的方式来写 sql。

更多内容移步代码库吧~

AsyncDao

asyncDao是一款异步非阻塞模型下的数据访问层工具。

MySQL only. 基于MySQL的异步驱动

借鉴了Mybatis的mapping 和 dynamicSQL的内容,Mybatiser可以无缝切换

注解表达SQL的能力

事务支持

SpringBoot支持

Mybatis like

使用上与Mybatis几乎一致,由于异步非阻塞的关系,数据的返回都会通过回调DataHandler来完成,所以方法定义参数的最后一个一定是DataHandler类型。由于需要提取方法的参数名,于是需要加上编译参数-parameters,请将它在IDE和maven里配置上。

public interface CommonDao {

void query(User user, DataHandler> handler);

void querySingle(User user, DataHandler handler);

void querySingleMap(User user, DataHandler handler);

void insert(User user,DataHandler handler);

void update(User user,DataHandler handler);

void delete(User user,DataHandler handler);

}

mapper.xml与Mybatis几乎一致的写法(覆盖常见标签,一些不常用标签可能不支持,动态SQL建议使用注解SQL功能)

select * from T_User

AND username = #{user.username}

OR age > #{user.age}

order by id desc

insert into T_User

old_address,

created_at,

password,

now_address,

state,

age,

username,

updated_at,

#{user.oldAddress},

#{user.createdAt},

#{user.password},

#{user.nowAddress},

#{user.state},

#{user.age},

#{user.username},

#{user.updatedAt},

update T_User

password=#{user.password},

age=#{user.age},

where id = #{user.id}

注解SQL

在XML里写SQL对于一些常见SQL实在是重复劳动,so这里允许你利用注解来表达SQL,该怎么做呢?

Table与Model关联

@Table(name = "T_User")

public class User {

@Id("id")

private Long id;

//建议全部用包装类型,并注意mysql中字段类型与java类型的对应关系,mysql的int不会自动装换到这里的long

private String username;

private Integer age;

@Column("now_address")

private String nowAddress;

@Column("created_at")

private LocalDateTime createdAt;

//asyncDao 里sql的时间类型都用joda,注意不是JDK8提供的那个,而是第三方包org.joda.time

@Ignore

private String remrk;

@Table记录数据表的名字 @Id记录主键信息 @Column映射了表字段和属性的关系,如果表字段和类属性同名,那么可以省略这个注解 @Ingore忽略这个类属性,没有哪个表字段与它关联。

定义接口

@Sql(User.class)

public interface CommonDao {

@Select(columns = "id,age,username")

@OrderBy("id desc")

@Page

@ModelConditions({

@ModelCondition(field = "username", criterion = Criterions.EQUAL),

@ModelCondition(field = "maxAge", column = "age", criterion = Criterions.LESS),

@ModelCondition(field = "minAge", column = "age", criterion = Criterions.GREATER)

})

void query(UserSearch userSearch, DataHandler> handler);

@Select(columns = "age,username")

@OrderBy("id desc")

void queryParam(@Condition String username,

@Condition(criterion = Criterions.GREATER) Integer age,

@OffSet int offset,

@Limit int limit,

DataHandler> handler);

@Select(columns = "username,age", sqlMode = SqlMode.COMMON)

void queryList(@Condition(criterion = Criterions.IN, column = "id") int[] ids, DataHandler> handler);

@Insert(useGeneratedKeys = true, keyProperty = "id")

void insert(User user, DataHandler handler);

@Update

@ModelConditions(@ModelCondition(field = "id"))

void update(User user, DataHandler handler);

@Delete

@ModelConditions(@ModelCondition(field = "id"))

void delete(User user, DataHandler handler);

}

看到这些注解你应该能猜出来SQL长什么样,接下来解释一下这些注解

查询

@Select(columns = "id,age,username")

@OrderBy("id desc")

@Page

@ModelConditions({

@ModelCondition(field = "username", criterion = Criterions.EQUAL),

@ModelCondition(field = "maxAge", column = "age", criterion = Criterions.LESS),

@ModelCondition(field = "minAge", column = "age", criterion = Criterions.GREATER)

})

void query(UserSearch userSearch, DataHandler> handler);

@Select

columns:默认 select *可以配置columns("username,age")选择部分字段;

SqlMode:有两个选择,SqlMode.SELECTIVE 和 SqlMode.COMMON,区别是selective会检查查询条件的字段是否为null来实现动态的查询,即值为null时不会成为查询条件。并且@Select,@Count,@Update,@Delete都有selective这个属性。

@Condition

criterion:查询条件,=,,in等,具体见Criterions

column:与表字段的对应,若与字段名相同可不配置

attach:连接 and,or, 默认是and

test:SqlMode为selective下的判断表达式,类似Mybatis里的test属性,动态化查询条件

@Limit,@OffSet为分页字段。

方法的参数不加任何注解一样会被当做查询条件,如下面两个函数效果是一样的:

@Select()

void queryUser(Integer age,DataHandler> handler);

@Select()

void queryUser(@Condition(criterion = Criterions.EQUAL, column = "age") Integer age,DataHandler> handler);

查询Model

上面的例子在查询条件比较多时方法参数会比较多,我们可以把查询条件封装到一个类里,使用@ModelConditions来注解查询条件,注意被@ModelConditions注解的方法只能有两个参数,一个是查询model,一个是DataHandler。

@Select

@Page

@ModelConditions({

@ModelCondition(field = "username", criterion = Criterions.EQUAL),

@ModelCondition(field = "minAge", column = "age", criterion = Criterions.GREATER),

@ModelCondition(field = "maxAge", column = "age", criterion = Criterions.LESS),

@ModelCondition(field = "ids", column = "id", criterion = Criterions.IN)

})

void queryUser5(UserSearch userSearch,DataHandler> handler);

@ModelCondition

field:必填,查询条件中类对应的属性

column:对应的表字段

test:动态SQL的判断表达式

@Page只能用在ModelConditions下的查询,并且方法参数的那个类应该有offset,limit这两个属性,或者 使用@Page(offsetField = "offset",limitField = "limit")指定具体字段

统计

@Count

void count(DataHandler handler);//返回Long类型

插入

@Insert(useGeneratedKeys = true, keyProperty = "id")//返回自增id

void insert(User user, DataHandler handler);

更新

@Update(columns = "username,age")//选择更新某几个列

void update(User user, DataHandler handler);//返回affectedRows

删除

@Delete

int delete(@Condition(criterion = Criterions.GREATER, column = "age") int min,

@Condition(criterion = Criterions.LESS, column = "age") int max,

DataHandler handler);

@Delete

@ModelConditions(@ModelCondition(field = "id"))

void delete(User user, DataHandler handler);

使用

简单的编程使用

AsyncConfig asyncConfig = new AsyncConfig();

PoolConfiguration configuration = new PoolConfiguration("username", "localhost", 3306, "password", "database-name");

asyncConfig.setPoolConfiguration(configuration);

asyncConfig.setMapperPackages("com.tg.async.mapper");//mapper接口

asyncConfig.setXmlLocations("mapper/");//xml目录,classpath的相对路径,不支持绝对路径

AsyncDaoFactory asyncDaoFactory = AsyncDaoFactory.build(asyncConfig);

CommonDao commonDao = asyncDaoFactory.getMapper(CommonDao.class);

UserSearch userSearch = new UserSearch();

userSearch.setUsername("ha");

userSearch.setMaxAge(28);

userSearch.setMinAge(8);

userSearch.setLimit(5);

CountDownLatch latch = new CountDownLatch(1);

commonDao.query(user, users -> {

System.out.println(users);

latch.countDown();

});

latch.await();

事务

Mybatis和Spring体系里有一个非常好用的@Translactional注解,我们知道事务本质就是依赖connection的rollback等操作,那么一个事务下多个SQL就要共用这一个connection,如何共享呢?传统的阻塞体系下ThreadLocal就成了实现这一点的完美解决方案。那么在异步世界里,要实现mybatis-spring一样的上层Api来完成事务操作是一件非常困难的事,难点就在于Api太上层,以至于无法实现connection共享。于是这里自能退而求其次,使用编程式的方式来使用事务,抽象出一个Translaction,具体的mapper通过translaction.getMapper()来获取,这样通过同一个Translaction得到的Mapper都将共用一个connection。

CountDownLatch latch = new CountDownLatch(1);

AsyncConfig asyncConfig = new AsyncConfig();

PoolConfiguration configuration = new PoolConfiguration("username", "localhost", 3306, "password", "database-name");

asyncConfig.setPoolConfiguration(configuration);

asyncConfig.setMapperPackages("com.tg.async.mapper");

asyncConfig.setXmlLocations("mapper/");

asyncDaoFactory = AsyncDaoFactory.build(asyncConfig);

asyncDaoFactory.startTranslation(res -> {

Translaction translaction = res.result();

System.out.println(translaction);

CommonDao commonDao = translaction.getMapper(CommonDao.class);

User user = new User();

user.setUsername("insert");

user.setPassword("1234");

user.setAge(28);

commonDao.insert(user, id -> {

System.out.println(id);

translaction.rollback(Void -> {

latch.countDown();

});

});

});

latch.await();

SpringBoot

虽然Spring5推出了WebFlux,但异步体系在Spring里依旧不是主流。在异步化改造的过程中,大部分人也往往会保留Spring的IOC,而将其他交给Vertx,所以asyncDao对于Spring的支持就是将Mapper注入IOC容器。

quick start

YAML配置文件:

async:

dao:

mapperLocations: /mapper #xml目录,classpath的相对路径,不支持绝对路径

basePackages: com.tg.mapper #mapper所在包

username: username

host: localhost

port: 3306

password: pass

database: database-name

maxTotal: 12

maxIdle: 12

minIdle: 1

maxWaitMillis: 10000

添加@Mapper来实现注入

@Mapper

@Sql(User.class)

public interface CommonDao {

@Select(columns = "id,age,username")

@OrderBy("id desc")

@Page(offsetField = "offset", limitField = "limit")

@ModelConditions({

@ModelCondition(field = "username", criterion = Criterions.EQUAL),

@ModelCondition(field = "maxAge", column = "age", criterion = Criterions.LESS),

@ModelCondition(field = "minAge", column = "age", criterion = Criterions.GREATER)

})

void query(UserSearch userSearch, DataHandler> handler);

}

通过@EnableAsyncDao来开启支持,简单示例:

@SpringBootApplication

@EnableAsyncDao

public class DemoApplication {

public static void main(String[] args){

ApplicationContext applicationContext = SpringApplication.run(DemoApplication.class);

CommonDao commonDao = applicationContext.getBean(CommonDao.class);

UserSearch userSearch = new UserSearch();

userSearch.setUsername("ha");

userSearch.setMaxAge(28);

userSearch.setMinAge(8);

userSearch.setLimit(5);

commonDao.query(userSearch, users -> {

System.out.println("result: " + users);

});

}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/534004.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跨域获取后台数据undefined_同源策略amp;JSONP跨域

同源策略&JSONP跨域同源策略 对于同源的定义,MDN给出了这样的解释:如果两个页面的协议,端口(如果有指定)和主机都相同,则两个页面具有相同的源。如何确定两个页面是否同源,只要比较两个页面…

python 除数不能为零的报错有哪些_【社区精选40】Python错误处理及代码调试方法(文末赠书中奖名单)...

本文整理自爱数据学院中的问答更多精彩问答,进入下方社区网站查看http://www.lovedata.cn/invitation社区精选话题 第40期Python错误处理及代码调试方法一次写完代码程序并能够正常运行的概率很小很小,总会有各种各样的错误bug需要处理。有的报错简单&a…

利用python批量查询企业信息_python实现批量获取指定文件夹下的所有文件的厂商信息...

本文实例讲述了python实现批量获取指定文件夹下的所有文件的厂商信息的方法。分享给大家供大家参考。具体如下:功能代码如下:import os, string, shutil,reimport pefileimport codecs, sysimport wximport struct#输出中打印Unicode字符#sys.stdout co…

mac mysql prefpane_【MySQL数据库开发之一】Mac下配置安装数据库-MySQL

本站文章均为那么从今天开始陆续会更新数据库和Hibernate框架的博文,也是Himi学习的历程记录,希望大家能共同讨论和研究;OK,本篇简单介绍安装吧,首先到MySQL官方网站:如上图:点击DOWNLOAD &…

系统新模块增加需要哪些步骤_想要吸引人流,儿童乐园需要增加哪些新设备呢...

儿童乐园是现今最火爆的一个投资项目,因为它的主要消费群体是孩子,而现在的家长们对孩子们的宠爱,基本都会答应让孩子们去儿童乐园里面玩耍。但是儿童乐园的投资经营者也会遇见一些小问题,例如儿童乐园添加设备要怎么选择呢&#…

php mysql 图像_php-向/从MySQL数据库插入/查看图像

我在DB中插入图像时遇到问题.该表具有以下结构:> id-> INT(3)->自动增量>名称-> VARCHAR(30)> extension-> VARCHAR(10)[可能太短]> img-> MEDIUMBLOB插入图像的PHP代码为:if($_FILES[file][error]0){$result is_uploaded_f…

照片打印预览正常打印空白_小米发布口袋照片打印机,可无墨打印3寸背胶照片...

9月11日消息,小米推出一款小米口袋照片打印机。与之前的小米米家照片打印机相比,这款新品更加小巧便携,体积接近充电宝大小,净重仅181g,便于随身携带。小米口袋照片打印机采用ZINK无墨技术打印,即使用嵌入纸…

c中获取python控制台输出_在真实的tim中用C捕获控制台python打印

我正在尝试从C创建一个python进程,并从python脚本获取打印结果。在这就是我的C代码:namespace ConsoleApp1{public class CreateProcess{public String PythonPath { get; set; }public String FilePath { get; set; }public String Arguments { get; se…

python三大编程语言_程序员最需要的三种编程语言

随着科学技术的进步和新技术的进步,编程语言的种类越来越多,变化是程序员需要跟踪和学习许多语言 然而,有太多的语言无法一一掌握 在目前的形式中,最需要掌握的三种编程语言是 现在判断还不晚 坦白说,找工作很容易 它可…

MySQL优化调优有没有做过_MySQL 调优/优化的 100 个建议

MySQL是一个强大的开源数据库。随着MySQL上的应用越来越多,MySQL逐渐遇到了瓶颈。这里提供 101 条优化 MySQL 的建议。有些技巧适合特定的安装环境,但是思路是相通的。我已经将它们分成了几类以帮助你理解。MySQL监控MySQL服务器硬件和OS(操作系统)调优&…

python语句print(type([1、2、3、4))_Python 学习第一天

一、学习内容1.print:表示输出print (“hello world”)单行注释:#多行注释:“““ ”””2.运算符注意:才表示等于,!表示不等于3.位运算符~按位取反:~104.变量和赋值teacher“老马的…

mysql核心参数_MySQL技术体系之核心参数

本文主要基于MySQL 5.7版本的数据库环境,总结my.cnf文件中核心参数的配置使用,让更多的人对MySQL技术体系有更全面、更专业的深度了解。一、客户端核心参数1、port端口号,默认33062、socketSocket文件地址,默认以.sock为文件名称后…

svd降维 python案例_SVD(奇异值分解)Python实现

注: 在《SVD(异值分解)小结 》中分享了SVD原理,但其中只是利用了numpy.linalg.svd函数应用了它,并没有提到如何自己编写代码实现它,在这里,我再分享一下如何自已写一个SVD函数。但是这里会利用到SVD的原理,…

salt 启动mysql_saltsack自动化配置day03:服务部署mysql部署

一、MySQL集群需求分享1、抽象:功能模块把基础的写成通用服务部署也要抽象出来模块redis内存有的多,有的少,可以config set在线更改redis 安装、配置、启动mysql 安装、配置(my.cnf可以统一 目录默认配置可以统一)master: server_id 1111slav…

jtag引脚定义_从逆向分析的角度学习硬件调试技巧JTAG,SSD和固件提取

我想从逆向的角度做了深入了解JTAG,JTAG是许多嵌入式CPU使用的硬件级别调试机制,我希望通过这篇文章从逆向工程师的角度解释如何使用JTAG,并在此过程中提供一些实际示例。0x01 研究目标通过这篇文章,我希望做到以下几点&#xff1…

python virtualenv conda_在vscode中启动conda虚拟环境的思路详解

问题:cudatoolkit cudnn 通过conda 虚拟环境安装,先前已经使用virtualenv安装tf,需要在conda虚拟环境中启动外部python虚拟环境思路:conda prompt即将 [虚拟环境位置] 以参数形式传入 [activate.bat]VSOCDE中的设置添加以下语句{&…

python如何导入图片imread_OpenCV 使用imread()函数读取图片的六种正确姿势

经常看到有人在网上询问关于imread()函数读取图片失败的问题。今天心血来潮,经过实验,总结出imread()调用的四种正确姿势。通常我要获取一张图片的绝对路径是这样做的:在图片上右键——属性——安全——对象名称。然后复制对象名称就得到了图…

python2.7与3.7脚本转换_python 2.7 - python 3.7 升级记录

更换的模块python 3.7 模块名python 2.7 模块名python 3.7 包python 2.7包pymysqlMySQLdbPyMySQLMySQL-pythonpdfminerpdfminerpdfminer.sixpdfminerurllib.parseurlparse自带自带htmlHTMLParser自带HTMLparser语法变化1. print 修改为 print()2. except Exception, e 修改为 e…

远程过程调用失败_Java开发大型互联网RPC远程调用服务实现之问题处理方案

引言RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络…

chrome 新的session 设置_为什么还是由这么多人搞不懂Cookie、Session、Token?

作者:不学无数的程序员链接:https://urlify.cn/Yfm6Vr# Cookie洛:大爷,楼上322住的是马冬梅家吧? 大爷:马都什么? 夏洛:马冬梅。 7大爷:什么都没啊? 夏洛…