Mysql4J MySQL ORM 组件开源项目

我要开发同款
匿名用户2020年03月03日
178阅读

技术信息

开源地址
https://gitee.com/ursa_minor/mysql4j
授权协议
MIT

作品详情

Mysql4J是一款用于访问MySQL数据库的ORM组件。通过它可以方便地构建sql语句,并且可在编译期进行sql语法检查,还可以把得到的数据结果转换成List、Map、Set等形式。简单易用,独辟蹊径,是提高代码编写效率的好工具。

Mysql4J适用于中小型项目。

特点底层基于Sprig的JdbcTemplate

Mysql4J底层通过Sprig的JdbcTemplate对象访问数据库,该JdbcTemplate对象需要事先配置好并保证可用,然后设置到Mysql4J中。

编译期纠错

Mysql4J可在编译期检查出大部分的sql语法错误,相比于在运行时才发现sql错误,对于快速开发,有很大帮助。

由于用java模拟了sql语句,所以sql的语法,对应到了java语法,这样当sql拼写不正确时(逻辑错误除外),通常也是一个java语法错误,如果使用IDE的代码提示工具,则基本的匹配和代码构建是自动提示的。

数据结果,封装友好

Mysql4J对查询得到的数据,可进行相对灵活的后处理。可以是pojo对象的List集合,也可以是Map集合。同JdbcTemplate不同,JdbcTemplate的getMap方法,仅返回Map表示的一条数据记录,Mysql4J则把多行查询结果,放在Map中,Map的key值,可以由程序员指定,通常指定成表中某个不重复的字段。还可以方便的直接得到单个值,或者某一列值的List列表。

如果不想定义pojo对象,可以直接使用Row对象封装行记录,Row实现了Map接口,提供了getStrig、getIteger、getDate等方便的数据提取方法。

Api简单易懂,上手迅速

Mysql4J的api非常简单,几乎不用阅读文档,仅根据javaIDE的代码工具提示,就可以构建完整的程序代码。

SQL即用即写,逻辑集中不分散

sql语句中,通常包含着关键的业务逻辑。Mysql4J可保证在一个java方法中,业务逻辑的完整性,sql语句不会被写到程序文件之外。打开一个类,逻辑全部在其内部展现,相对于把sql写到xml中,代码更清晰易读。

使用Mysql4J的使用非常简单,例如:

//表(mappig类)um_memberm=ewum_member();//查询对象Queryquery=ewQuery();query.from(m);query.where(m.level.eq(1));query.where(m.ame.startsWith("urs"));query.where(m.ick.cotais("小熊"));query.where(m.reg_time.le(ewDate(),DATETIME));query.order(m.reg_time.desc());query.limit(0,20);//获得结果集Listlist=query.getList();其中um_member为数据库表,类名直接对应表名,也是Mysql4J的mappig类,用来配置表结构。um_memberm=ewum_member(),变量m,可理解为表的别名,m.level,m.ame,m.ick,m.reg_time是m对象的属性名,同时也是表um_member的字段名!

这样映射后,数据库中表名和字段名的改变,只需要修改mappig类um_member,然后分布在程序各处的Mysql4J数据库访问代码,会自动报出编译期错误,方便修改,保证了表名和字段名的一致。类似报出编译期错误警告的地方还有很多,比如把数字赋值给一个字符字段,等等。

Mysql4J不仅把表和字段直接映射成java的类和属性,而且把查询、插入、修改、删除数据的操作,也做了对象化处理。这些都采用java实现并且尽量遵循sql的语法习惯!

编写mappig类

使用Mysql4J,需要配置一个mappig类。在传统的ORM组件中,这个配置通常以xml格式写在文件里,用来指明java数据模型和数据库中的表以及字段的映射关系。在Mysql4J中,这个配置就是一个java类,它不仅说明了映射关系,还能被实例化成一个对象,在数据操作中使用。

具体使用方法如下:

首先假设数据库中存在如下的表:

//会员表CREATETABLE`um_member`(   `id`bigit(20)NOTNULLAUTO_INCREMENT,   `ame`varchar(20)DEFAULTNULL,   `ick`varchar(30)DEFAULTNULL,   `level`smallit(6)DEFAULTNULL,   `tel`varchar(20)DEFAULTNULL,   `reg_time`datetimeDEFAULTNULL,   `last_logi_time`datetimeDEFAULTNULL,   `logi_times`it(11)DEFAULTNULL,   PRIMARYKEY(`id`))ENGINE=IoDBDEFAULTCHARSET=utf8它的配置类则按照如下方式书写:

//类名=表名:类名需要同数据库表名保持完全一致,该类必须继承Table作为父类publicclassum_memberextedsTable{//构造方法的固定写法publicum_member(){//数据映射对象的class,可以为Row.class或者pojo对象的class,这里采用pojo对象super(Member.class);//初始化,固定写法,不可省略super.iit();//获得可用的JdbcTemplate对象JdbcTemplatejdbcTemplate=(JdbcTemplate)YourSprig.get("jdbcTemplate");//设置jdbcTemplatesuper.setJdbcTemplate(jdbcTemplate);}//属性名=字段名:属性名需要同数据库字段名保持完全一致publicNumid=ewNum().asPrimaryKey().asIcremet();//主键IDpublicChrame;//姓名publicChrick;//昵称publicNumlevel;//会员等级publicChrtel;//电话publicDatetimereg_time=ewDatetime().property("registerTime");//注册时间publicDatetimelast_logi_time;//最近登录时间publicNumlogi_times;//登录次数}该类继承了c.com.ursamior.mysql4j.core.Table类,Table类是所有配置类的父类,配置类必须继承此类,继承该类不需要实现任何抽象方法。

配置类的类名,必须同表名相同,这可能违反了java的命名规范,但使得配置类在使用时,更像一个表,而不是一个对象。

配置类由两部分组成,一个是构造方法,一个是成员变量,不需要普通的方法。

构造方法对参数无要求,内部要求必须调用下列父类的方法:

一个是父类构造方法super(Classcls),用来指定数据查询结果的装载对象,即封装数据的pojo对象,如果没有pojo对象,可以直接使用Row,即super(Row.class)。

另一个是super.iit(),该方法负责初始化工作,必须调用,不可省略。

第三个是super.setJdbcTemplate(jdbcTemplate),jdbcTemplate对象需要使用者自行获取,并保证可用。

后两个方法可以合并成super.iit(jdbcTemplate)。

把jdbcTemplate绑定到配置类,可以自然地支持多数据库情况。并且在使用时,无须再设置jdbcTemplate,只需要简单实例化配置类即可:

um_memberm=ewum_member();配置类中,需要配置同表字段一一对应的成员变量,成员变量的名称,必须同表的字段名保持一致,如:

publicNumlogi_times;这里也可能会违反java的命名规范,但这使配置类应用起来更像一个表。类名和属性名如果不同数据库的表名字段名保持一致,将导致sql拼写错误。

成员变量必须被声明为public的,并且只能是Chr、Num、Datetime三种类型之一。Chr代表该属性对应数据库的字符型字段,Num代表该属性对应数据库的数字型字段,Datetime目前只针对datetime类型字段,其它字段类型,会在后续版本扩展。

如果字段不需要其它的修饰,则不需要被赋值,仅保持声明即可,super.iit()方法会自动给它们赋值一个对应的对象,不会出现属性为ull的情况。如果需要其它修饰,比如设置为主键、设置为自增长、设置pojo类中的对应属性,则需要手动配置。如:

publicNumid=ewNum().asPrimaryKey().asIcremet();publicDatetimereg_time=ewDatetime().property("registerTime");这里,id属性被设置成主键,并且是自增长类型。reg_time属性被指定了pojo类中对应的属性为registerTime。如果pojo类中对应的属性为regTime,则不需要上述语句,super.iit()会自动转化并为其赋值。

配置类可重复使用,虽然配置类是有状态的,但在使用过程中,其状态不会发生改变,可以构建一个配置类的工厂类,也可将配置类作为单例模式写到Sprig中。最简单的使用方式,直接ew一个就好:um_memberm=ewum_member();

编写pojo类

pojo类是一个普通的装载数据的对象,遵循JavaBea风格,不需要继承和实现任何父类和接口。

如果表的主键是自增长的,新增记录后的主键值,会自动设置到pojo类中,该pojo类需要有主键的setter方法。

一个表如果有对应的pojo类,则需要在配置类构造方法的super(Classcls)中设置,比如

super(Member.class);Member类源码如下:

//会员对象publicclassMember{privateLogid;//主键IDprivateStrigame;//姓名privateStrigick;    //昵称privateItegerlevel;//会员等级privateStrigtel;//电话privateDateregisterTime;//注册时间privateDatelastLogiTime;//最近登录时间privateItegerlogiTimes;//登录次数publicLoggetId() {returid;}publicvoidsetId(Logid) {this.id=id;}//省略其它属性的getter/setter方法}使用Row

如果不使用自定义的pojo类装载数据,Mysql4j提供了Row类来装载数据。Row实现了Map接口,提供了getStrig、getIteger、getDate等方便的数据提取方法。可以作为Map的替代。

如果表的主键是自增长的,新增记录后的主键值,会自动设置到Row类中。

使用Query查询数据

Query类是Mysql4J的查询类,通过它可以方便的构建大多数的select语句。并且方便地得到想要的数据结果。

A:例1

//值itlevel=2;Strigame="ur";Strigick="小熊";Datedate=ewDate(System.curretTimeMillis()-7*24*60*60*1000);//表um_memberm=ewum_member();//构建sqlQueryquery=ewQuery();query.from(m);                             //fromum_member mquery.where(m.level.eq(level));               //m.level=2query.where(m.ame.startsWith(ame));        //m.amelike'ur%'query.where(m.ick.cotais(ick))            //m.icklike'%小熊%' .ullIgore();             //如果Strig变量ick为空,则忽略m.icklike...query.where(m.reg_time.ge(date,DATETIME));   //m.reg_time>='2020-01-0217:42:09'query.order(m.reg_time.desc());               //orderbym.reg_time descquery.limit(0,20);                           //limit0,20//执行List<Member>list=query.getList(Member.class);上述语句生成sql为:

selectt0.id,t0.ame,t0.ick,t0.level,t0.tel,t0.reg_time,t0.last_logi_time,t0.logi_timesfromum_membert0wheret0.level=2adt0.amelike'ur%'adt0.icklike'%小熊%'adt0.reg_time>='2020-01-0217:42:09'orderbyt0.reg_timedesclimit0,20表别名实际为t0,同变量名m不一致,不会导致任何问题。下同。

B:例2

//值itlevel=2;Datedate=ewDate(System.curretTimeMillis()-7*24*60*60*1000);//表um_memberm=ewum_member();um_order_formof=ewum_order_form();//query支持链式方法调用Queryquery=ewQuery()query.from(m)                            //fromum_member m .from(of,m.id.eq(of.m_id))             //,um_order_form ofwherem.id=of.m_id.select(m.ame)                       //selectm.ame.select(Fu.sum(of.cout).as("cout"))  //sum(of.cout)ascout.where(m.level.eq(level))               //m.level=2.where(m.reg_time.ge(date,DATETIME))   //m.reg_time>='2020-01-0217:42:09'.havig(Fu.sum(of.cout).ge(5))        //havigsum(of.cout)>=5.group(m.ame);                      //groupbym.ame//执行List<Member>list= query.getList(Member.class);上述语句生成sql为:

selectt2.ame,sum(t3.cout)ascoutfromum_membert2,um_order_formt3wheret2.id=t3.m_idadt2.level=2adt2.reg_time>='2020-01-0217:42:09'groupbyt2.amehavigsum(t3.cout)>=5C:例3

//表um_memberm=ewum_member();um_order_formof=ewum_order_form();//子查询Querysub=ewQuery().from(of)                        //fromum_order_form of.select(of.m_id)                   //selectof.m_id.havig(Fu.sum(of.cout).ge(5))   //havigsum(of.cout)>=5.group(of.m_id);                   //groupbyof.m_id//构建sqlQueryquery=ewQuery();query.from(m);                       //fromum_membermquery.where(m.id.i(sub));           //wherem.idi(...)//执行List<Member>list= query.getList(Member.class);上述语句生成sql为:

selectt5.id,t5.ame,t5.ick,t5.level,t5.tel,t5.reg_time,t5.last_logi_time,t5.logi_timesfromum_membert5wheret5.idi(selectt6.m_idfromum_order_formt6groupbyt6.m_idhavigsum(t6.cout)>=5)得到特定结构的查询结果

Query对象返回的数据结果,可以有多种形式。

方法说明List<R>getList()返回以List形式表示的结果集,元素类型<R>为配置类中指定的class,List的元素可以为pojo对象或者Row对象ItegergetCout()返回忽略分页后的结果行数,用于分页查询中VgetValue(Class<V>valueClass)返回一个值,值的类型由valueClass指定,比如Strig.class、Iteger.class。当数据结果有多条记录时,仅返回第一条记录;当没有匹配结果时,返回ull。该方法要求select关键字指定且仅指定一列。List<V>getValues(Class<V>valueClass)返回值的List,元素类型由valueClass指定,比如Strig.class、Iteger.class。当没有匹配结果时,返回空的List对象。该方法要求select关键字指定且仅指定一列。Set<V>getSet(Class<V>valueClass)返回值的Set,元素类型由valueClass指定,比如Strig.class、Iteger.class。当没有匹配结果时,返回空的Set对象。该方法要求select关键字指定且仅指定一列。RgetOe()返回一条记录,数据类型<R>为配置类中指定的class,List的元素可以为pojo对象或者Row对象。当没有匹配结果时,返回ull。Map<Object,R>getMap(Strigproperty)返回以Map形式表示的结果集,需要指定key,即pojo的property。Value的类型<R>为配置类中指定的class。value可以为pojo对象或者Row对象。当没有匹配结果时,返回空的Map对象。Map<K,R>getMap(KeyCallback<K,R>keyCallback)

返回以Map形式表示的结果集,通过回调获得属性值作为key。Value的类型<R>为配置类中指定的class。value可以为pojo对象或者Row对象。当没有匹配结果时,返回空的Map对象。Map<K,V>getMap(KeyValueCallback<K,V,R>keyValueCallback)

返回以Map形式表示的结果集。<R>指定了最初返回数据的类型,为配置类中指定的class。该方法通过回调获得属性值作为key和value。当没有匹配结果时,返回空的Map对象。 

 

 

 

 

 

 

 

使用Iserter插入数据

如果要在表中插入新数据,可使用Iserter类,Iserter类用来构建isert语句并提交。

举例:

A:使用值创建一个isert语句

//表um_memberm=ewum_member();//值Strigame="ursamior";Strigick="小熊";Itegerlevel=1;Strigtel="1234567890";DateregisterTime=ewDate();DatelastLogiTime=ull;ItegerlogiTimes=0;//构建sqlIserteriserter=ewIserter(m);          //isertitoum_memberiserter.set(m.ame,ame);                //ame, //'ursamior'iserter.set(m.ick,ick);                   //ick,  //'小熊'iserter.set(m.level,level);                 //level, //1iserter.set(m.tel,tel);                     //tel,  //'1234567890'iserter.set(m.reg_time,registerTime);        //reg_time, //'2020-01-0217:42:09'iserter.set(m.last_logi_time,lastLogiTime);  //last_logi_time,//ulliserter.set(m.logi_times,logiTimes);       //logi_times, //0//提交iserter.execute();上述语句生成sql为:

isertitoum_member(ame,ick,level,tel,reg_time,last_logi_time,logi_times)values('ursamior','小熊',1,'1234567890','2020-01-0917:42:09',ull,0)B:使用pojo/Row对象创建一个isert语句

//表um_memberm=ewum_member();//pojo对象Membermember=ewMember();member.setName("ursamior");member.setNick("小熊");member.setLevel(1);member.setTel("1234567890");member.setRegisterTime(ewDate());//提交Iserter.isert(m,member);上述语句生成sql为:

isertitoum_member(ame,ick,level,tel,reg_time,last_logi_time,logi_times)values('ursamior','小熊',1,'1234567890','2020-01-0917:42:09',ull,ull)C:Iseter还可以生成isertito...select...语句

//表um_memberm=ewum_member();um_order_formof=ewum_order_form();//值itlevel=2;Datedate=ewDate(System.curretTimeMillis()-7*24*60*60*1000);//Query对象,用来生成select语句Queryquery=ewQuery();query.from(m);                           //fromum_membermquery.select(m.id.as(of.m_id));              //selectm.idasm_idquery.select(Fu.eval("1").as(of.cout));       //1ascoutquery.select(Fu.eval("8.00").as(of.price));    //8.00aspricequery.where(m.level.ge(level));              //wherem.level>=2query.where(m.reg_time.ge(date,DATETIME)); //m.reg_time>='2020-01-0217:42:09'      //构建sqlIserteriserter=ewIserter(of);          //isertitoum_order_formiserter.colums(of.m_id,of.cout,of.price);   //(m_id,cout,price)iserter.with(query);                    //select...//执行iserter.execute();上述语句生成sql为:

isertitoum_order_form(m_id,cout,price)    selectt11.idasm_id,1ascout,8.00aspricefromum_membert11wheret11.level>=2adt11.reg_time>='2020-01-0217:42:09'如果表的主键是自增长的,新增记录后的主键值,会自动设置到pojo类中,该pojo类需要有主键的setter方法。

如果没有使用pojo类,而是使用Row类型,则主键值也会自动设置。

使用Updater修改数据

如果要修改表中的数据,可使用Updater类,Updater类用来构建update语句并提交。

举例:

A:使用值创建一个update语句

//表um_memberm=ewum_member();//要修改的值Logid=2020L;Strigick="小熊";Itegerlevel=1;Strigtel="1234567890";DatelastLogiTime=ewDate();ItegerlogiTimes=1;//构建sqlUpdaterupdater=ewUpdater(m);          //updateum_member mupdater.set(m.ick,ick);                   //setm.ick='小熊'updater.set(m.level,level);                  //m.level=1updater.set(m.tel,tel);                      //m.tel='1234567890'updater.set(m.last_logi_time,lastLogiTime);  //m.last_logi_time='2020-01-0917:42:09'updater.set(m.logi_times,logiTimes);       //m.logi_times=1updater.where(m.id.eq(id));            //wherem.id=2020//执行updater.execute();上述语句生成sql为:

updateum_membert14sett14.ick='小熊',t14.level=1,t14.tel='1234567890',t14.last_logi_time='2020-01-0917:42:09',t14.logi_times=1wheret14.id=2020B:使用pojo/Row对象创建一个update语句

//表um_memberm=ewum_member();//pojo类Membermember=ewMember();member.setId(2020L);member.setName("ursamior");member.setNick("小熊");member.setLevel(1);//执行Updater.update(m,member);上述语句生成sql为:

updateum_membersetame='ursamior',ick='小熊',level=1,tel=ull,reg_time=ull,last_logi_time=ull,logi_times=ullwhereid=2020C:Updater还可以生成带有select子句的update语句

//表um_memberm=ewum_member();um_order_formof=ewum_order_form();//临时表classTempTableextedsQuery{publicNumid;}//临时表就是一个Query对象TempTablett=ewTempTable();tt.from(of);                      //fromum_order_form oftt.select(of.m_id.as(tt.id));          //selectof.m_idasidtt.group(of.m_id);                 //groupbyof.m_idtt.havig(Fu.cout(of.id).ge(10));    //havigcout(of.id)>=10//构建sqlUpdaterupdater=ewUpdater(m);    //updateum_member mupdater.with(tt,tt.id.eq(m.id));      //(select...)tt wherett.id=m.idupdater.set(m.level,2);               //setm.level=2//执行updater.execute();上述语句生成sql为:

updateum_membert16,(selectt17.m_idasidfromum_order_formt17groupbyt17.m_idhavigcout(t17.id)>=10)t18sett16.level=2wheret18.id=t16.id使用Deleter删除数据

如果要删除表中的数据,可使用Deteler类,Deleter类用来构建delete语句并提交。

举例:

A:使用值创建一个delete语句

//表um_memberm=ewum_member();//值Itegerlevel=1;//构建sqlDeleterdeleter=ewDeleter(m);        //deletemfromum_membermdeleter.where(m.level.eq(level));         //wherem.level=1//提交deleter.execute();上述语句生成sql为:

deletet19fromum_membert19wheret19.level=1B:使用pojo/Row对象创建一个delete语句

//表um_memberm=ewum_member();//pojo对象Membermember=ewMember();member.setId(2020L);//提交Deleter.delete(m,member);上述语句生成sql为:

deletefromum_memberwhereid=2020C:Deleter还可以生成带有select子句的delete语句

//表um_memberm=ewum_member();um_order_formof=ewum_order_form();//临时表classTmextedsQuery{publicNumid;}//临时表就是一个Query对象Tms=ewTm();s.from(of);                         //fromum_order_formofs.select(of.m_id.as(s.id));             //selectof.m_idasids.group(of.m_id);                   //groupbyof.m_ids.havig(Fu.cout(of.id).ge(10));      //havigcout(of.id)>=10//构建sqlDeleterdeleter=ewDeleter(m);      //deletemfromum_membermdeleter.with(s,s.id.eq(m.id));         //(select...)swheres.id=m.id//执行deleter.execute();上述语句生成sql为:

deletet21fromum_membert21,(selectt22.m_idasidfromum_order_formt22groupbyt22.m_idhavigcout(t22.id)>=10)t23wheret23.id=t21.id

功能介绍

Mysql4J是一款用于访问MySQL数据库的ORM组件。通过它可以方便地构建sql语句,并且可在编译期进行sql语法检查,还可以把得到的数据结果转换成List、Map、Set等形式。简单易用,...

声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态

评论