吞吐量(TPS)、QPS、并发数、响应时间(RT)概念
开发的原因,需要对吞吐量(TPS)、QPS、并发数、响应时间(RT)几个概念做下了解,查自百度百科,记录如下: 1. 响应时间(RT) 响应时间是指系统对请求作出响应的时间。直观上看,这个指标与人对软件性能的主观感受是非常一致的,因为它完整地记录了整个计算机系统处理请求的时间。由于一个系统通常会提供许多功能,而不同功能的处理逻辑也千差万别,因而不同功能的响应时间也不尽相同,甚至同一功能在不同输入数据的情况下响应时间也不相同。所以,在讨论一个系统的响应时间时,人们通常是指该系统所有功能的平均时间或者所有功能的最大响应时间。当然,往往也需要对每个或每组功能讨论其平均响应时间和最大响应时间。 对于单机的没有并发操作的应用系统而言,人们普遍认为响应时间是一个合理且准确的性能指标。需要指出的是,响应时间的绝对值并不能直接反映软件的性能的高低,软件性能的高低实际上取决于用户对该响应时间的接受程度。对于一个游戏软件来说,响应时间小于100毫秒应该是不错的,响应时间在1秒左右可能属于勉强可以接受,如果响应时间达到3秒就完全难以接受了。而对于编译系统来说,完整编译一个较大规模软件的源代码可能需要几十分钟甚至更长时间,但这些响应时间对于用户来说都是可以接受的。 2. 吞吐量(Throughput) 吞吐量是指系统在单位时间内处理请求的数量。对于无并发的应用系统而言,吞吐量与响应时间成严格的反比关系,实际上此时吞吐量就是响应时间的倒数。前面已经说过,对于单用户的系统,响应时间(或者系统响应时间和应用延迟时间)可以很好地度量系统的性能,但对于并发系统,通常需要用吞吐量作为性能指标。 对于一个多用户的系统,如果只有一个用户使用时系统的平均响应时间是t,当有你n个用户使用时,每个用户看到的响应时间通常并不是n×t,而往往比n×t小很多(当然,在某些特殊情况下也可能比n×t大,甚至大很多)。这是因为处理每个请求需要用到很多资源,由于每个请求的处理过程中有许多不走难以并发执行,这导致在具体的一个时间点,所占资源往往并不多。也就是说在处理单个请求时,在每个时间点都可能有许多资源被闲置,当处理多个请求时,如果资源配置合理,每个用户看到的平均响应时间并不随用户数的增加而线性增加。实际上,不同系统的平均响应时间随用户数增加而增长的速度也不大相同,这也是采用吞吐量来度量并发系统的性能的主要原因。一般而言,吞吐量是一个比较通用的指标,两个具有不同用户数和用户使用模式的系统,如果其最大吞吐量基本一致,则可以判断两个系统的处理能力基本一致。 3. 并发用户数 并发用户数是指系统可以同时承载的正常使用系统功能的用户的数量。与吞吐量相比,并发用户数是一个更直观但也更笼统的性能指标。实际上,并发用户数是一个非常不准确的指标,因为用户不同的使用模式会导致不同用户在单位时间发出不同数量的请求。一网站系统为例,假设用户只有注册后才能使用,但注册用户并不是每时每刻都在使用该网站,因此具体一个时刻只有部分注册用户同时在线,在线用户就在浏览网站时会花很多时间阅读网站上的信息,因而具体一个时刻只有部分在线用户同时向系统发出请求。这样,对于网站系统我们会有三个关于用户数的统计数字:注册用户数、在线用户数和同时发请求用户数。由于注册用户可能长时间不登陆网站,使用注册用户数作为性能指标会造成很大的误差。而在线用户数和同事发请求用户数都可以作为性能指标。相比而言,以在线用户作为性能指标更直观些,而以同时发请求用户数作为性能指标更准确些。 4. QPS每秒查询率(Query Per Second) 每秒查询率QPS是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准,在因特网上,作为域名系统服务器的机器的性能经常用每秒查询率来衡量。对应fetches/sec,即每秒的响应请求数,也即是最大吞吐能力。 (看来是类似于TPS,只是应用于特定场景的吞吐量) from:https://www.cnblogs.com/data2value/p/6220859.html
View Detailsphp输出所有错误信息
方法一 修改php.ini
1 2 3 4 5 6 |
;显示错误信息 display_errors = On ;显示php开始错误信息 display_startup_errors = On ;日志记录错误信息 log_errors = On |
方法二 需要调试的php文件首行中加入
1 2 3 4 |
ini_set('display_errors',1); //错误信息 ini_set('display_startup_errors',1); //php启动错误信息 error_reporting(-1); //打印出所有的 错误信息 ini_set('error_log', dirname(__FILE__) . '/error_log.txt'); //将出错信息输出到一个文本文件 |
from:https://blog.csdn.net/whatday/article/details/50833934
View DetailsLaravel项目修改时区
最近做了一个支付宝支付的应用,现在还在开发过程中,今天早上起床之后先调试了一下项目,模拟支付了一笔(¥9999.00) 2333支付宝的沙箱环境啦,屌丝程序猿哪来这么多钱…… 打开Navicat查看数据库的时候,意外发现created_at字段的时间不大对啊,少了8小时,显示凌晨4点创建的支付订单。(没错,我睡到12点才起来的) 然后,首先意识到了PHP的时区配置不对,立即打开Wamp环境查看了一下,timezone是。。。Asia/Shanghai。额,这就很不科学了啊 接下来很自然就想到了Laravel的问题,打开Laravel的/app/config/app.php配置文件,发现里面果然有这么一行:
1 2 3 |
<span class="ot">[</span> <span class="st"><span class="hljs-string">'timezone'</span></span> => <span class="st"><span class="hljs-string">'UTC'</span></span><span class="ot">,</span> <span class="ot">]</span> |
哦好吧,果然是这里的问题。 由于我喜欢配置文件集中管理,并且Laravel不是有一个.env配置文件么,那就好好利用一下吧。 观察配置文件里其他内容发现,有一个env()函数,猜测这个就是从.env中获取配置项value的函数了,不管怎么样,先试一下就对了,试试又不会怀孕嘛…… 试着对app.php做了如下改动
1 2 3 |
<span class="ot">[</span> <span class="st"><span class="hljs-string">'timezone'</span></span> => env<span class="ot">(</span><span class="st"><span class="hljs-string">'TIMEZONE'</span></span><span class="ot">,</span><span class="st"><span class="hljs-string">'UTC'</span></span><span class="ot">),</span> <span class="ot">]</span> |
在.env文件中添加一行TIMEZONE=Asia/Shanghai之后,重新创建了一笔交易,用沙箱支付宝支付了一下,诶,可行 -_- 好了,就是这样,Laravel修改时区的教程到此结束,看我啰嗦了这么多,其实也就那两句。 from:https://www.cnblogs.com/wxjblog/p/6940195.html
View Detailsjavaweb利用filter拦截未授权请求
项目上有个小需求,要限制访问者的IP,屏蔽未授权的请求。该场景使用过滤器来做再合适不过了。 SecurityFilter.java:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
public class SecurityFilter implements Filter { private Log log = LogFactory.getLog(SecurityFilter.class); private List<String> whitelist = new ArrayList<String>(); private List<String> regexlist = new ArrayList<String>(); private static final String _JSON_CONTENT = "application/json; charset=UTF-8"; private static final String _HTML_CONTENT = "text/html; charset=UTF-8"; private static final String _403_JSON = "{'code': '403', 'msg': '访问被拒绝,客户端未授权!'}"; private static final String _403_HTML = "<html><body><div style='text-align:center'><h1 style='margin-top: 10px;'>403 Forbidden!</h1><hr><span>@lichmama</span></div></body></html>"; @Override public void destroy() { } @Override public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletrequest; HttpServletResponse response = (HttpServletResponse) servletresponse; if (isSecurityRequest(request)) { filterchain.doFilter(request, response); } else { log.info("拒绝来自[" + request.getRemoteAddr() + "]的访问请求:" + request.getRequestURI()); response.setStatus(403); if (isAjaxRequest(request)) { response.setContentType(_JSON_CONTENT); response.getWriter().print(_403_JSON); } else { response.setContentType(_HTML_CONTENT); response.getWriter().print(_403_HTML); } } } @Override public void init(FilterConfig filterconfig) throws ServletException { String allowedIP = filterconfig.getInitParameter("allowedIP"); if (allowedIP != null && allowedIP.length() > 0) { for (String item : allowedIP.split(",\\s*")) { // 支持通配符* if (item.contains("*")) { String regex = item.replace(".", "\\.").replace("*", "\\d{1,3}"); regexlist.add(regex); } else { whitelist.add(item); } } } } /** * 判断当前请求是否来自可信任的地址 * * @param request * @return */ private boolean isSecurityRequest(HttpServletRequest request) { String ip = request.getRemoteAddr(); for (String item : whitelist) { if (ip.equals(item)) return true; } for (String item : regexlist) { if (ip.matches(item)) return true; } return false; } /** * 判断请求是否是AJAX请求 * @param request * @return */ private boolean isAjaxRequest(HttpServletRequest request) { String header = request.getHeader("X-Requested-With"); if (header != null && header.length() > 0) { if ("XMLHttpRequest".equalsIgnoreCase(header)) return true; } return false; } } |
web.xml增加配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<filter> <filter-name>securityFilter</filter-name> <filter-class>com.lichmama.webdemo.filter.SecurityFilter</filter-class> <init-param> <param-name>allowedIP</param-name> <param-value>192.168.5.*</param-value> </init-param> </filter> <filter-mapping> <filter-name>securityFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
from:https://www.cnblogs.com/lichmama/p/7063587.html
View DetailsJava获取此次请求URL以及服务器根路径的方法
本文介绍了Java获取此次请求URL以及获取服务器根路径的方法,并且进行举例说明,感兴趣的朋友可以学习借鉴下文的内容。 一、 获取此次请求的URL 1 2 3 4 5 6 String requestUrl = request.getScheme() //当前链接使用的协议 +"://" + request.getServerName()//服务器地址 + ":" + request.getServerPort() //端口号 + request.getContextPath() //应用名称,如果应用名称为 + request.getServletPath() //请求的相对url + "?" + request.getQueryString(); //请求参数 举例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 http://127.0.0.1:8080/world/index.jsp?name=lilei&sex=1 <Context path="world" docBase="/home/webapps" debug="0" reloadable="true"/> request.getScheme() = "http"; request.getServerName() = "127.0.0.1"; request.getServerPort() = "8080"; request.getContextPath() = "world"; request.getServletPath() = "index.jsp"; request.getQueryString() = "name=lilei&sex=1"; http://127.0.0.1:8080/world/index.jsp?name=lilei&sex=1 <Context path="" docBase="/home/webapps" debug="0" reloadable="true"/> request.getScheme() = "http"; request.getServerName() = […]
View Detailsjava 通过user-agent获取客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/**java获取客户端*/ public static void getPlatform(HttpServletRequest request){ /**User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器 能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等*/ String agent= request.getHeader("user-agent"); //客户端类型常量 String type = ""; if(agent.contains("iPhone")||agent.contains("iPod")||agent.contains("iPad")){ type = "ios"; } else if(agent.contains("Android") || agent.contains("Linux")) { type = "apk"; } else if(agent.indexOf("micromessenger") > 0){ type = "wx"; }else { type = "pc"; } return pc; } |
from:https://blog.csdn.net/mr_caoshuai/article/details/78284010
View Details数据持久化和ORM的概念
1.数据持久化的概念 数据持久化就是将内在中的数据模型转换为存储模型,以及将存储模型转换为内在中的数据模型的统称,数据模型可以是任何数据结构或对象模型,例如JavaBean对象;存储模型可以是关系型数据库表,XML文件,二进制文件等. 2.什么是ORM ORM(Object/Relational Mapping)中文翻译为对象/关系型数据映射,它也可以理解为一种数据持久化技术,其主要是把对象模型,例如JavaBean对象和关系型数据库的表建立对应关系,并且提供了一个通过JavaBean对象去操作数据库表的机制. 3.使用ORM技术的好处 在实际开发中,程序员使用面向对象的技术操作数据,而当要把数据存储起来时,使用的却是关系型数据库,这样就造成了很多的不便,ORM在对象模型和关系数据库的表之间建立了一座桥梁,有了它,程序员就不需要再使用SQL语句操作数据库中的表,直接操作JavaBean对象就可以实现数据的存储,查询,更改和删除等操作,Hibernate就是这样一种技术. from:http://www.djjwz.com/news/news4034.html
View Details理解ORM和数据持久化
一,什么是ORM 对象关系映射(Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),用于在关系型数据库和业务实体对象之间作一个映射。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。说白了就是把关系型数据库封装成业务实体对象,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法。 对象关系映射(Object-Relational Mapping)提供了概念性的、易于理解的模型化数据的方法。ORM方法论基于三个核心原则:
1 2 3 |
简单:以最基本的形式建模数据。 传达性:数据库结构被任何人都能理解的语言文档化。 精确性:基于数据模型创建正确标准化的结构。 |
典型地,建模者通过收集来自那些熟悉应用程序但不熟练数据结构的人的信息开发信息的模型。建模者必须能够用非技术专家可以理解的术语在概念层次上与数据结构进行通讯。建模者也必须能以简单的单元分析信息,对样本数据进行处理。ORM专门被设计为改进这种联系。简单的说:ORM相当于中继数据。 二,理解ORM 对象-关系映射(Object-Relational Mapping,简称ORM),是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。 面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。 让我们从O/R开始。字母O起源于 对象(Object),而R则来自于 关系(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。 当你开发一个应用程序的时候不使用O/R Mapping,你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。你在DAL中写了很多的方法来读取对象数据,改变状态对象等等任务。而这些代码写起来总是重复的。 如果打开你最近的程序,看看DAL代码,你肯定会看到很多近似的通用的模式。我们以保存对象的方法为例,你传入一个对象,为SQLCOMMAND对象添加SQLPARAMETER,把所有属性和对象对应,设置SQLCOMMAND的COMMANDTEXT属性为存储过程,然后运行SQLCOMMAND。对于每个对象都要重复的写这些代码。 除此之外,还有更好的办法吗?有,引入一个O/R Mapping。实质上,一个O/R Mapping会为你生成DAL。与其自己写DAL代码,不如用O/R Mapping。你用O/R Mapping保存,删除,读取对象,O/R Mapping负责生成SQL,你只需要关心对象就好。 一般的ORM包括以下四部分:
1 2 3 4 |
一个对持久类对象进行CRUD操作的API; 一个语言或API用来规定与类和类属性相关的查询; 一个规定Mapping METADATA的工具; 一种技术可以让ORM的实现同事务对象一起进行DIRTYCHECKING, LAZY ASSOCIATION FETCHING以及其他的优化操作。 |
三,ORM优缺点 ORM自其概念被提出,就得到了无数的响应,花样繁多的应用框架更是应接不暇。可见,他是有其独到的优势的。那么他的优势有哪些那: 第一:
1 2 |
ORM最大的优势,隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。 他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。 |
第二:
1 2 |
ORM使我们构造固化数据结构变得简单易行。在ORM年表的史前时代,我们需要将我们的对象模型转化为一条一条的SQL语句, 通过直连或是DB helper在关系数据库构造我们的数据库体系。而现在,基本上所有的ORM框架都提供了通过对象模型构造关系数据库结构的功能。这,相当不错。 |
世上没有驴是不吃草的(又想好又想巧,买个老驴不吃草),任何优势的背后都隐藏着缺点,这是不可避免的: 第一:
1 2 |
无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(早期,这是所有不喜欢ORM人的共同点)。 现在的各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。 |
第二:
1 2 |
面向对象的查询语言(X-QL)作为一种数据库与对象之间的过渡,虽然隐藏了数据层面的业务抽象, 但并不能完全的屏蔽掉数据库层的设计,并且无疑将增加学习成本. |
第三:
1 |
对于复杂查询,ORM仍然力不从心。虽然可以实现,但是不值的。视图可以解决大部分calculated column,case ,group,having,order by, exists,但是查询条件(a and b and not c and (d or d))。。。。。。 |
四,正确看待ORM ORM为何而生 在数月以前,我有幸参加了一个公司内部的组件发布会。令我深感意外的事,一向无人关心的组件发布会这次变得人山人海,在漫长的新版本介绍之后。每个开发组长都跳出来抱怨上一个版本的问题,并且宣布与刚发布的新版本也是无法满足他们的需要的。一切都是如此的混乱,以至领导层不得不采用镇压的方式来平息怒火冲天的人们。 在会后的那个晚上,我仔细回想了这次冲突。因为据我了解,这一系列的组件非常完美的完成了他所被期待的功能。可是为什么还是会被抱怨如此那。 我觉得,可能,他(组件)是没有被正确使用了。 不知道还有谁记得James Elliott的那句话:
1 2 3 4 |
As good object-oriented developers got tired of this repetitive work, their typical tendency towards enlightened laziness started to manifest itself in the creation of tools to help automate the process. When working with relational databases, the culmination of such efforts were object/relational mapping tools. |
ORM构架只能是一个helper,他定位与此,而不是完整的数据持久层。他的设计者从来就没把他定位于取代一切的超级美女。ORM致力为长久以来的程序员与”重复劳动”的战争而助拳。与任何一个helper一样,他有自己的不足,他有优点也有缺点。 无数的开发人员试图将使用ORM的框架构架自己项目的数据持久层,很多人感受到了ORM的优势,他们欢心鼓舞。但是很不幸,也有很多人失败或是深受蹉责。 还有许多人,无奈的编写着很多ORM不适合作的事情。其实想一想,被自己舍弃了的以前的helper工具,难道真的一无是处了? ORM与DB Helper Library 很多人可能都接触过这类的helper,每个公司都有自己的helper。许多Helper提供了很多的强大的功能,封闭交互底层,实体类支持,提供SQL翻译功能。ORM比之这些Helper只是多提供了一层,他尝试封闭的自动化的(或是映射文件)来实现关联。以前,这都是我们手打的。(灵活替换数据库也算ORM优点,ORM优势和缺点。。。(小雨)) 问题就在与有些人发现封闭的自动化关联满足他们需要了,所以ORM对他而言是成功的。而有些人发现封闭的自动化关联不适合他们的项目,所以ORM被诟病。 我的观点是ORM试图取代helper,为此提供了更多的功能。他为了应付更加严格和复杂的企业需求而不断发展,在很多情况下,这些工具开始具有自身的复杂性,使得开发人员必须学习使用它们的详细规则,并修改组成应用程序的类以满足映射系统的需要,使用它们所面临的复杂性反而盖过了所能获得的好处。在我们的大部分项目中Helper依然是我们构建数据持久层的主力,ORM或许在有些项目(模块)中可以独揽一切,但是ORM(就目前而言)无法面对一切考验。 五,数据持久化 上面有提到很多人使用ORM的框架构架项目的数据持久层,什么事数据持久层?这就要理解数据持久化了。 理解数据持久化 数据持久化就是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称. 数据模型可以是任何数据结构或对象模型,存储模型可以是关系模型、XML、二进制流等。 狭义的理解,持久化仅仅是指把对象数据永久保存在数据库中,数据在计算机中一般由两个存储地,内存为暂存,数据库可以理解为永存;广义的理解,持久化包括和数据库相关的各种操作,封装了数据访问细节,为大部分业务逻辑提供面向对象的API。 简单的理解持久化可以在二个层面:应用层和系统层:
1 2 |
应用层:如果关闭(shutdown)你的应用然后重新启动则先前的数据依然存在。 系统层:如果关闭(shutdown)你的系统(电脑)然后重新启动则先前的数据依然存在。 |
数据持久化好处 使用数据持久化有以下好处:
1 2 3 |
1、松散耦合,程序代码重用性强,使持久化不依赖于底层数据库和上层业务逻辑实现,更换数据库时只需修改配置文件而不用修改代码。 2、业务逻辑代码可读性强,在代码中不会有大量的SQL语言,提高程序的可读性。 3、持久化技术可以自动优化,以减少对数据库的访问量,提高程序运行效率。 |
数据持久化对象的基本操作有:保存、更新、删除、查询等。 由此可知,数据持久层也就是与数据交互的那一层次,所以有时候有见到ORM框架介绍:是一个数据持久层(ORM)框架。 from:https://blog.csdn.net/u012585964/article/details/52412520
View Detailslinux centos7 network is unreachable 上不了网
新安装的linux,ping命令报错: network is unreachable 使用service network start ,错误信息如下: Failed to start LSB: Bring up/down networking 解決方式:新安装系统的ifcfg-ech0未设置 指令如下: vi /etc/sysconfig/network-scripts/ifcfg-eth0 将如下信息加入文本中: DEVICE=eth0 BOOTPROTO=static BROADCAST=192.168.1.255 IPADDR=192.168.1.25 NETMASK=255.255.255.0 GATEWAY=192.168.1.254 ONBOOT=yes HWADDR=XX:XX:XX:XX:XX:XX DNS1=XXX.XXX.XXX.XXX 其中: HWADDR为机器物理地址,通过如下命令 link/ether为物理地 修改完成之后,重启网络服务,出现如下提示: service network restart ok,现在ping一下: 网络正常。 原文:http://www.2cto.com/os/201306/218110.html from:http://blog.sina.com.cn/s/blog_7d31bbee0102v6ws.html
View DetailsMyBatis
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。 iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)。 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
View Details