Mysql4J是一款用于访问MySQL数据库的ORM组件。通过它可以方便地构建sql语句,并且可在编译期进行sql语法检查,还可以把得到的数据结果转换成List、Map、Set等形式。简单易用,独辟蹊径,是提高代码编写效率的好工具。
Mysql4J适用于中小型项目。特点底层基于Sprig的JdbcTemplateMysql4J底层通过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点击空白处退出提示
评论