自己编写一首现代诗个ORM应该怎么做

很多人都不太认可以第三方ORM,因为考虑的点不够全面,没有用户群体大的ORM有保证,这点是不可否认确是事实。
但是往往用户群体大的ORM又有不足之处,就拿用户群体最多的两个ORM来说一下吧
EF性能够用,但是总体还是和轻量级ORM有一定差距,如果没有差距就没有Dapper什么事儿了。
性能不错,兼容也好但是就是语法太少,基本都要手写SQL,或自已扩展,自己扩展考虑的点可能连第三方ORM都不如,只能够自已需求使用,发现问题自已来改,没发现问题也挺安逸。
我的ORM之旅
1、感谢大家的帮助
第一 &要感谢上海蓝灯数据科技股份有限公司给我构架师一职让.NET部门都使用我的技术框架
第二 &百签软件的老总的大力支持除了自已员工使用外还帮我喧传
第三 &群(&)里的朋友向我提了很多保贵的问题和改进的建议。
第四 &chloe.ORM的作者,两个人都为了ORM基情四射
2、谈一谈开发SqlSugarORM框架中遇到的一些坑
而这些坑我发现博客园的一些其它ORM也普遍存在,所以我将这些问题一一的分享,也希望更多人能够指出SqlSugar的不足之处。
(1)、避免Sql执时计划失效
&Sql执行计划是什么,简单的说就是让Sql服务器更明确的知道你要做什么,将你的操作步骤存起来,下一次遇到同样的SQL便使用同样的操作步骤 ,大大降低SQL操作的步骤,提高性能,引起的性能差距可能是成倍的 。
参数化比拼SQL性能高的原因,也就是因为调用了系统存储过程 sp_executesql 将Sql执行计划的优势发挥了出来
如下图 name的长度为11,因为sqlparameter没有指定Size 所以nvarchar的数字是动态的,所以会导致Sql执行计划无效,一般的性能测试很难测出来,这种情况将会打乱Sql执行计划,当参数越多,参数的长度越大性能差距越明显。
而固定长度的测试根本发现不了。
解决方案:
将SqlParameter size&4000
全部设为4000,EF和Dapper在这点上就做的非常的棒
例如出现 id&1&&id&0处理两个相同的名字参数时& id&@id and id&@id+随机数 &&
只要加了随机数就无法进执行计划了
解决方案:
自增数 id&@id and id&@id1
2、数据类形转换成实体的处理
这一点就Dapper做的最好,EF也不错给出了很明确的错误信息。
为什么说Dapper做的最好呢,因为Dapper能把数据的int转换成实体类中的string。数据库是string转换成int时就给出了非常明确的错误信息。
目前第三方ORM都没在这方面做很好的处理
解决方案:
需要做很细的类型判段,我的做法是在Emit生成Dynamicbuilder之前处理,用数据库类型和实体类体做对比,将异常提前抛出,没有异常EMIT对象将存进缓存,预热后不会在执行。
3、性能的突破
就单纯拿Emit将DataReader转成List&T&来说,第三方的ORM基本上都做到了比Dapper快或者说平分秋色。
预热后一次查询100万条数据这是最好的测试方式,但要注意一点 如果走的是 DataReader的索引器 那就会有性能损耗
GetValue和索引器都是Object类型执行转换后将会产生 拆箱(将OBJECT转成了值类型),SqlSugar能在这个方面得到改进,多亏Chloe.ORM作者帮我发现了这个问题
4、拉姆达解析性能
如何测试自已拉姆达解析成SQL过程花时间多长呢,
测试方法:每执行一次只查询一条数据,WHERE条件多设一点。执行次数10000以上。
解决方案:在解析过程中千万不能用&Expression.Lambda(exp).Compile().DynamicInvoke();&
用了这种写法将会带来十倍的性能之差,按上面的测试方式很容易测出性能的瓶颈。
越短的时间内执行的次数越多越容易体现出来。
发布到Nuget2周时间不到
我已经提交了这么多次修改
SqlSugar的用法和介简:&,欢迎您的建议
最后我只想说一句,不是第三方ORM不能用,而是你们并没有把问题指出来,代码开源就是为了让大家一起进步,一起改进。
只要作者有激情,有上进心,还担心什么呢。
阅读(...) 评论()简单来说,他跟你直接用一个sqlUtil的实现是一样,只不过很多复杂的util优化的事情,提前有其他程序员做了。&br&Mybatis是一个映射封装,他与你用util的区别就是,他将在代码块中的sql存在统一的xml文件也就是sqlmaper中。同时他将你执行sql的传参也就是执行变量进行了通配,然后映射到你的model中。&br&Mybatis大概的执行过程:&br&通过factory方法获取sqlsession----通过MapperProxy代理到dao--执行底层数据库操作,简单说就是跟楼上说的&b&“&/b&&b&据经过controller 再经过service 然后执行service中的相关方法并关联到mapper 再执行mapper.xml中的sql语句=== &a data-hash=&50de32a1b62a32bfcfd1f031bfb0083b& href=&///people/50de32a1b62a32bfcfd1f031bfb0083b& class=&member_mention& data-hovercard=&p$b$50de32a1b62a32bfcfd1f031bfb0083b&&@象厂喜剧&/a&
”&/b&&br&我们以JDBC为例看看他们的区别:&br&JDBC:&br&&p&(1)
加载JDBC驱动,建立并获取数据库连接 ,创建statement对象&/p&&p&(2)
设置SQL语句的传入参数&/p&&p&(3)
执行SQL语句并获得查询结果&/p&&p&(4)
对查询结果进行转换处理并将处理结果返回&/p&&p&(5)
释放资源&/p&&p&Mybatis:&/p&&p&1:使用连接池,datasource,在驱动并连接的这个过程中优化并解耦&/p&&p&
JDBC第一步其实从效率角度来看是不合适的,因为无论什么数据库都不可能支撑随机和庞大的连接数,而且不可避免的存在连接浪费的情况,Mybatis就封装了这些优化的方法。&br&&/p&&p&2:统一sql存取到XML&/p&&p&
如果代码写在java块中,在团队合作中很可能出现两个交叉业务的代码使用类似的sql语句,而开发人员的工作本身没有交集,那就代表sql语句肯定是无法复用的。而且对sql的修改,就代表着对java文件的修改,需要重新编译和打包部署(比如常见的状态值更改,sql修改随着业务变化必然存在修改)。&/p&&p&
mybatis将sql统一存取到xml中,就算存在业务交叉,但因为统一配置的缘故,sql在xml中一目了然,两个跨team的程序员可以看到对方的sql,来判断自己是否需要重用。并且使用xml配置可以减少代码编译。&/p&&p&
还有就是在java中拼写长sql太恶心了。&/p&&p&3:参数和结果集映射&/p&&p&
sql的方式需要传入参数,如果存在多条件“或类型”的查询(列表查询的查询条件允许空),那就代表你必须传参进行sql拼接,就算使用xml的方式也不行。要么每个业务独立配置xml中的sql,要么还是写入java代码中,或者以工具的方式进行自动拼接。&/p&&p&
Mybatis使用映射的方式,方便model管理参数,同时以解析器的方式将参数动态拼接到sql(sqlmaper里那些标签),由于是model映射,连查询结果都可以统一映射,方便取出和运算。而且mybatis对查询结果集进行了缓存处理,使得重复查询进一步进行了优化。&/p&&p&4:对多重复sql进行复用封装&/p&&p&
比如模板方法,将常用sql模块化,直接调用。比如通用的save和getID之类的,只有表名和字段名有变化。&/p&
简单来说,他跟你直接用一个sqlUtil的实现是一样,只不过很多复杂的util优化的事情,提前有其他程序员做了。 Mybatis是一个映射封装,他与你用util的区别就是,他将在代码块中的sql存在统一的xml文件也就是sqlmaper中。同时他将你执行sql的传参也就是执行变…
如 &a data-hash=&ecc0ec035f& href=&///people/ecc0ec035f& class=&member_mention& data-editable=&true& data-title=&@vczh& data-hovercard=&p$b$ecc0ec035f&&@vczh&/a& 所说,lambda表达式不是一个函数,而是一个Expression&&&br&&br&&div class=&highlight&&&pre&&code class=&language-csharp&&&span class=&n&&Expression&/span& &span class=&n&&firstArg&/span& &span class=&p&&=&/span& &span class=&n&&Expression&/span&&span class=&p&&.&/span&&span class=&n&&Constant&/span&&span class=&p&&(&/span&&span class=&m&&2&/span&&span class=&p&&);&/span&
&span class=&n&&Expression&/span& &span class=&n&&secondArg&/span& &span class=&p&&=&/span& &span class=&n&&Expression&/span&&span class=&p&&.&/span&&span class=&n&&Constant&/span&&span class=&p&&(&/span&&span class=&m&&3&/span&&span class=&p&&);&/span&
&span class=&n&&Expression&/span& &span class=&k&&add&/span& &span class=&p&&=&/span& &span class=&n&&Expression&/span&&span class=&p&&.&/span&&span class=&n&&Add&/span&&span class=&p&&(&/span&&span class=&n&&firstArg&/span&&span class=&p&&,&/span& &span class=&n&&secondArg&/span&&span class=&p&&);&/span&
&span class=&n&&Console&/span&&span class=&p&&.&/span&&span class=&n&&WriteLine&/span&&span class=&p&&(&/span&&span class=&k&&add&/span&&span class=&p&&);&/span&
&/code&&/pre&&/div&&br&把以上代码构建为以下表达式树:&br&&img src=&/727845fdda28eabb6e570d3d_b.png& data-rawwidth=&444& data-rawheight=&284& class=&origin_image zh-lightbox-thumb& width=&444& data-original=&/727845fdda28eabb6e570d3d_r.png&&&br&将表达式树编译为委托:&br&&div class=&highlight&&&pre&&code class=&language-text&&Expression firstArg = Expression.Constant(2);
Expression secondArg = Expression.Constant(3);
Expression add = Expression.Add(firstArg, secondArg);
Func&int& compiled = Expression.Lambda&Func&int&&(add).Compile();
Console.WriteLine(compiled());
&/code&&/pre&&/div&&br&从LINQ to Objects和LINQ to SQL生成SQL的方式略有不同:&img src=&/6cc1ba9fdbc3d21f0cfaa_b.png& data-rawwidth=&641& data-rawheight=&426& class=&origin_image zh-lightbox-thumb& width=&641& data-original=&/6cc1ba9fdbc3d21f0cfaa_r.png&&&br&&br&注:图来自 &a data-hash=&ecc0ec035f& href=&///people/ecc0ec035f& class=&member_mention& data-editable=&true& data-title=&@vczh& data-hovercard=&p$b$ecc0ec035f&&@vczh&/a& 推荐的 Csharp in Depth.3rd
所说,lambda表达式不是一个函数,而是一个Expression&& Expression firstArg = Expression.Constant(2);
Expression secondArg = Expression.Constant(3);
Expression add = Expression.Add(firstArg, secondArg);
Console.WriteLine(add); 把以…
我从2006年开始,翻译过SQLAlchemy、Django、SQLObject的文档。你自己去看看英文文档就知道了,SQLAlchemy那是给人看的么?一个ORM而已,搞了1000页的文档,而且字特别密集,废话一萝筐。我都怀疑写文档的人是不是在用英文的某种文言文在写,简单的话,却几乎各种同义生词,奇怪语法。&br&&br&英文文档里一个对立面可以参考Flask的文档,那叫一个简单易懂。&br&&br&年,我依次完成了SQLObject和SQLAlchemy的文档后(部分翻译)。发现SQLObject在逐渐没落(现在很多人都没听说过了)。而SQLAlchemy又是如此奇葩的存在。就只好搞定了DBUtils,然后就不再用任何ORM了。&br&&br&以我的观点,ORM是在SQL之上的封装,而这种封装引入了太厚的封装,使得程序员对底层的控制力明显减弱,又加入了太多新的设计。所以我是不赞同使用ORM的,还是干干净净的SQL好用的多。
我从2006年开始,翻译过SQLAlchemy、Django、SQLObject的文档。你自己去看看英文文档就知道了,SQLAlchemy那是给人看的么?一个ORM而已,搞了1000页的文档,而且字特别密集,废话一萝筐。我都怀疑写文档的人是不是在用英文的某种文言文在写,简单的话,却几…
作为一个有着从sql程度员到ORM狂热爱好者,然后又回归到原始sql开发的程度员,我想描述一下我的历程:&br&&br&刚工作时,我们使用esql c以及4gl方式编写数据库应用(2000年前的事情,今天估计用的人很少了)。因为是第一份工作,没有比较,也无法评述好与不好。&br&&br&然后java出来,我算是第一代的java程度员,第一时间热爱上了这个玩具(当时是jdk1.0,1.1的时代,连jdbc都没有),我自己移植过rpc,实现过基于jni的数据库访问。2000年后,j2ee很快就成为行业高大尚的技术,ejb更是神一般的技术。当时我也加入到这个粉丝圈中,不为别的,既然是面向对象,当然应该釆用对象化的技术,思维来操作数据库。(一个背景是基于jdbc编写的数据库应用实在是无比啰嗦)。当时还基于BCEL自己实现了一个容器外的类ejb的API,在我们自己的一个项目中进行了应用。&br&&br&后来有了hibernate,也第一时间跟进,感概脱离了ejb容器的轻量以及第一时间得以阅读一个完整的ORM实现源代码,再回思相比自己曾经的原型实现,强了太多太多。也开始在项目中推广hinernate。那段时间,不使用hibernate在java圈中都不好意思。比ejb1简单好用多了。&br&&br&不过,我开始怀念esql和4gl的时代,每当评审项目代码,看到一大堆的问题时,我就在想,用这种方式写代码,完全沒有esql时代的简单直接:&br&1. 程度员大都不了解数据库的细节,看到的都是对象,连字段的长度,底层类型,约束都不了解了。而我们当年,这一切了然于怀。(当然,这不是ORM的问题,但它确实让程度员远离了schema)&br&2.虽然ORM对简单的数据库操作可以很好实现,但一旦涉及到关联查询,修改,就复杂了,无论是ejb还是hibernate,都引入了自己的查询语言。原谅我,每隔一段时间,我又要重查手册才知道怎么写了&br&3. 本来是一行sql可以完成的代码,orm后多了很多代码,而且效率也大打折扣。&br&&br&代码评审多了,我就更加回忆起esql和4gl的好处来,我们现在做如此多的封装,真的就简化了吗,这不就是一行或者几行sql就可以完成的吗?&br&&br&大概是2009年,看到了groovy中的sql模式,当时有种回到了esql的感觉。大致了解后,开始在我们的系统中应用,干掉hibernate,使用groovy sql来替代。由于groovy的弱类型性质和解释执行,我们只使用它来编写sql密集的代码。&br&&br&再后来,mybatis开始普及,某种程度也是sql的回归。&br&&br&现在,我们的团队正在使用基于我开发的一个scala-sql(&a class=& wrap external& href=&///?target=http%3A///wangzaixiang/scala-sql& target=&_blank& rel=&nofollow noreferrer&&wangzaixiang/scala-sql 路 GitHub&i class=&icon-external&&&/i&&/a&)的库,(这个库直接借鉴了groovy sql)回归到最接近我刚工作时的esql模式,不再有容器,不再需要mapping,不再需要一个新的查询语言,(对了,也不用担心注入),也抛弃掉了DAO,服务中直接访问数据库,去除掉为了层次而层次的抽象。这一切当然要感谢scala语言的强大表达能力。&br&&br&作为一个样例,附一段代码,不管你喜不喜欢,反正,现在最符合我的胃口:&br&&div class=&highlight&&&pre&&code class=&language-scala&&
&span class=&k&&def&/span& &span class=&n&&rejectToPurchase&/span&&span class=&o&&()&/span&&span class=&k&&:&/span& &span class=&kt&&Unit&/span& &span class=&o&&=&/span& &span class=&o&&{&/span&
&span class=&k&&val&/span& &span class=&n&&orderItems&/span& &span class=&k&&=&/span& &span class=&n&&getOrderItemsByOrderId&/span&&span class=&o&&(&/span&&span class=&n&&entity&/span&&span class=&o&&.&/span&&span class=&n&&id&/span&&span class=&o&&)&/span&
&span class=&k&&val&/span& &span class=&n&&orderItemIds&/span& &span class=&k&&=&/span& &span class=&n&&orderItems&/span&&span class=&o&&.&/span&&span class=&n&&map&/span&&span class=&o&&(&/span&&span class=&k&&_&/span&&span class=&o&&.&/span&&span class=&n&&id&/span&&span class=&o&&)&/span&
&span class=&k&&val&/span& &span class=&n&&purchaseOrders&/span& &span class=&k&&=&/span& &span class=&n&&rows&/span&&span class=&o&&[&/span&&span class=&kt&&PurchaseOrder&/span&&span class=&o&&](&/span&&span class=&n&&sql&/span&&span class=&s&&&SELECT po.* FROM purchase_order_item poi LEFT JOIN purchase_order po ON po.id=poi.purchase_order_id WHERE poi.order_item_id in &&/span& &span class=&o&&+&/span& &span class=&n&&buildSqlIn&/span&&span class=&o&&(&/span&&span class=&n&&orderItemIds&/span&&span class=&o&&))&/span&
&span class=&c1&&//更新采购合同=新建&/span&
&span class=&k&&for&/span& &span class=&o&&(&/span&&span class=&n&&purchaseOrder&/span& &span class=&k&&&-&/span& &span class=&n&&purchaseOrders&/span&&span class=&o&&)&/span&
&span class=&n&&esql&/span&&span class=&o&&(&/span&&span class=&n&&sql&/span&&span class=&s&&&&&&/span&
&span class=&s&&
update purchase_order set&/span&
&span class=&s&&
updated_by = ${ServiceContext.operatorId},&/span&
&span class=&s&&
status = ${PurchaseOrderStatus.INIT}&/span&
&span class=&s&&
where id= ${purchaseOrder.id}&/span&
&span class=&s&&
&&&&/span&&span class=&o&&)&/span&
&span class=&n&&esql&/span&&span class=&o&&(&/span&&span class=&n&&sql&/span&&span class=&s&&&&&&/span&
&span class=&s&&
update orders set&/span&
&span class=&s&&
updated_by = ${ServiceContext.operatorId},&/span&
&span class=&s&&
contract_flag = ${OrderContractFlag.UNCONFIRMED}&/span&
&span class=&s&&
where id= ${entity.id}&/span&
&span class=&s&&
&&&&/span&&span class=&o&&)&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&
作为一个有着从sql程度员到ORM狂热爱好者,然后又回归到原始sql开发的程度员,我想描述一下我的历程: 刚工作时,我们使用esql c以及4gl方式编写数据库应用(2000年前的事情,今天估计用的人很少了)。因为是第一份工作,没有比较,也无法评述好与不好。 然…
&div class=&highlight&&&pre&&code class=&language-text&&http://my.oschina.net/KingPan/blog/280167#OSC_h1_1
&/code&&/pre&&/div&&br&正如大多数持久层框架一样,MyBatis 同样提供了&strong&一级缓存&/strong&和&strong&二级缓存&/strong&的支持。&br&&br&1.缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。&br&2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。&br&3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。&br&&br&&br&mybatis的一级缓存作用就是在同一个session过程中,将会对相同数据的存取不通过数据库,而是通过缓存机制提高效率,看测试代码&br&&img src=&/c225e22b0d00f228767e_b.png& data-rawwidth=&307& data-rawheight=&347& class=&content_image& width=&307&&&div class=&highlight&&&pre&&code class=&language-text&&import java.io.IOE
import java.io.InputS
import junit.framework.TestC
import org.apache.ibatis.io.R
import org.apache.ibatis.session.SqlS
import org.apache.ibatis.session.SqlSessionF
import org.apache.ibatis.session.SqlSessionFactoryB
import org.junit.T
import com.guowuxin.mybatis.mapper.UserM
import com.guowuxin.mybatis.model.U
create table user(
id int primary key auto_increment,
username varchar(50) unique,
password varchar(100),
useraddress varchar(50)
insert into user values(1,&guowuxin&,&guowuxin&,&beijing&);
insert into user values(1,&guoxiaoming&,&guowuxin&,&beijing&);
//如果两次查询都是查询1 将只会发送一条sql语句到数据库,否则将是2条sql语句
public class TestClass extends TestCase{
public static SqlSessionFactory sqlSessionF
String resource = &mybatis-config.xml&;
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactoy = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
public void testgetUserById() {
SqlSession sqlSession = sqlSessionFactoy.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User u1=mapper.getUserById(1);
System.out.println(u1);
User u2=mapper.getUserById(1);
System.out.println(u2);
} finally {
sqlSession.close();
&/code&&/pre&&/div&&div class=&highlight&&&pre&&code class=&language-text&&package com.guowuxin.mybatis.
import com.guowuxin.mybatis.model.U
//通过面向接口的mybatis编程方式,需要保证方法名和配置文件中的id名称一致
public interface UserMapper {
public User getUserById(int id);
&/code&&/pre&&/div&&div class=&highlight&&&pre&&code class=&language-text&&package com.guowuxin.mybatis.
public class User {
private String userN
private String userA
public int getId() {
public void setId(int id) {
public String getUserName() {
return userN
public void setUserName(String userName) {
this.userName = userN
public String getUserAddress() {
return userA
public void setUserAddress(String userAddress) {
this.userAddress = userA
public int getAge() {
public void setAge(int age) {
this.age =
public String toString()
final StringBuilder builder = new StringBuilder();
builder.append(&id=&).append(id).append(&,&);
builder.append(&age=&).append(age).append(&,&);
builder.append(&userName=&).append(userName).append(&,&);
builder.append(&userAddress=&).append(userAddress).append(&.&);
return builder.toString();
&/code&&/pre&&/div&&div class=&highlight&&&pre&&code class=&language-text&&log4j.rootLogger=DEBUG,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d %t %-5p (%c) - %m%n
.ibatis=DEBUG
.mon.jdbc.SimpleDataSource=DEBUG
.mon.jdbc.ScriptRunner=DEBUG
.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
&/code&&/pre&&/div&&br&&div class=&highlight&&&pre&&code class=&language-text&&&?xml version=&1.0& encoding=&UTF-8&?&
&!DOCTYPE configuration PUBLIC &-//mybatis.org//DTD Config 3.0//EN&
&http://mybatis.org/dtd/mybatis-3-config.dtd&&
&configuration&
&typeAliases&
&typeAlias alias=&User& type=&com.guowuxin.mybatis.model.User& /&
&/typeAliases&
&environments default=&development&&
&environment id=&development&&
&transactionManager type=&JDBC& /&
&dataSource type=&POOLED&&
&property name=&driver& value=&com.mysql.jdbc.Driver& /&
&property name=&url& value=&jdbc:mysql://127.0.0.1:3306/guowuxin& /&
&property name=&username& value=&root& /&
&property name=&password& value=&admin& /&
&/dataSource&
&/environment&
&/environments&
&mapper resource=&UserMapper.xml& /&
&/mappers&
&/configuration&
&/code&&/pre&&/div&&div class=&highlight&&&pre&&code class=&language-text&&&?xml version=&1.0& encoding=&UTF-8& ?&
&!DOCTYPE mapper
PUBLIC &-//mybatis.org//DTD Mapper 3.0//EN&
&http://mybatis.org/dtd/mybatis-3-mapper.dtd&&
&!-- 这里namespace必须是PostsMapper接口的路径,不然要运行的时候要报错 “is not known to the MapperRegistry”--&
&mapper namespace=&com.guowuxin.mybatis.mapper.UserMapper&&
&!-- 这儿的resultType是配置在mybatis-config.xml中得别名 --&
&select id=&getUserById& parameterType=&int& resultType=&User&&
select * from user where id=#{id}
&/code&&/pre&&/div&&br&结果:&br&&div class=&highlight&&&pre&&code class=&language-text&&....................
20:12:37,568 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]
20:12:37,568 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==&
Preparing: select * from user where id=?
20:12:37,586 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==& Parameters: 1(Integer)
id=1,age=0,userName=guowuxin,userAddress=beijing.
id=1,age=0,userName=guowuxin,userAddress=beijing.
20:12:37,593 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]
20:12:37,593 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]
20:12:37,593 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Returned connection 3874052 to pool.
&/code&&/pre&&/div&&br&如果取得2个不同的id&br&&div class=&highlight&&&pre&&code class=&language-text&&.......................
20:12:57,655 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Created connection 3874052.
20:12:57,656 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]
20:12:57,656 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==&
Preparing: select * from user where id=?
20:12:57,664 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==& Parameters: 1(Integer)
id=1,age=0,userName=guowuxin,userAddress=beijing.
20:12:57,679 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]
20:12:57,679 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==&
Preparing: select * from user where id=?
20:12:57,679 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==& Parameters: 2(Integer)
id=2,age=0,userName=guoxiaoming,userAddress=beijing.
20:12:57,679 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]
20:12:57,679 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]
20:12:57,679 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Returned connection 3874052 to pool.
&/code&&/pre&&/div&&br&&br&&br&二级缓存机制指的则是在不同的session之间都可以共享相同的数据内容。&br&&div class=&highlight&&&pre&&code class=&language-text&&import java.io.IOE
import java.io.InputS
import org.apache.ibatis.io.R
import org.apache.ibatis.session.SqlS
import org.apache.ibatis.session.SqlSessionF
import org.apache.ibatis.session.SqlSessionFactoryB
import org.junit.T
import com.guowuxin.mybatis.mapper.UserM
import com.guowuxin.mybatis.model.U
import junit.framework.TestC
public class TestTwoCache extends TestCase{
public static SqlSessionFactory sqlSessionF
String resource = &mybatis-config.xml&;
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
public void testCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
User u1=mapper1.getUserById(1);
System.out.println(u1);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
User u2=mapper2.getUserById(1);
System.out.println(u2);
} finally {
sqlSession1.close();
sqlSession2.close();
&/code&&/pre&&/div&在没有开启二级缓存之前,将会执行两次sql语句。&br& 20:28:10,786 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - PooledDataSource forcefully closed/removed all connections.&br& 20:28:10,850 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Openning JDBC Connection&br& 20:28:11,011 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Created connection 3874052.&br& 20:28:11,012 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]&br& 20:28:11,013 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==&
Preparing: select * from user where id=? &br& 20:28:11,030 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==& Parameters: 1(Integer)&br&id=1,age=0,userName=guowuxin,userAddress=beijing.&br& 20:28:11,040 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Openning JDBC Connection&br& 20:28:11,154 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Created connection .&br& 20:28:11,154 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@1c0ec97]&br& 20:28:11,154 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==&
Preparing: select * from user where id=? &br& 20:28:11,154 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==& Parameters: 1(Integer)&br&id=1,age=0,userName=guowuxin,userAddress=beijing.&br& 20:28:11,154 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]&br& 20:28:11,154 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@3b1d04]&br& 20:28:11,154 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Returned connection 3874052 to pool.&br& 20:28:11,154 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c0ec97]&br& 20:28:11,154 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@1c0ec97]&br& 20:28:11,154 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Returned connection
to pool.&br&&br&------------------------&br&在实体类映射文件中加入&cache/&&br&&div class=&highlight&&&pre&&code class=&language-text&&&?xml version=&1.0& encoding=&UTF-8& ?&
&!DOCTYPE mapper
PUBLIC &-//mybatis.org//DTD Mapper 3.0//EN&
&http://mybatis.org/dtd/mybatis-3-mapper.dtd&&
&!-- 这里namespace必须是PostsMapper接口的路径,不然要运行的时候要报错 “is not known to the MapperRegistry”--&
&mapper namespace=&com.guowuxin.mybatis.mapper.UserMapper&&
&!-- 这儿的resultType是配置在mybatis-config.xml中得别名 --&
&select id=&getUserById& parameterType=&int& resultType=&User&&
select * from user where id=#{id}
&/code&&/pre&&/div&&br&&div class=&highlight&&&pre&&code class=&language-text&& 10:15:11,162 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Created connection .
10:15:11,164 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@157aa53]
10:15:11,164 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==&
Preparing: select * from user where id=?
10:15:11,182 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==& Parameters: 1(Integer)
id=1,age=0,userName=guowuxin,userAddress=beijing.
10:15:11,196 main DEBUG (org.apache.ibatis.cache.decorators.LoggingCache) - Cache Hit Ratio [com.guowuxin.mybatis.mapper.UserMapper]: 0.5
id=1,age=0,userName=guowuxin,userAddress=beijing.
10:15:11,196 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@157aa53]
10:15:11,196 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@157aa53]
10:15:11,197 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Returned connection
&/code&&/pre&&/div&就会发现cache命中,只执行了一次sql语句&br&&br&------------------------------&br&如果二级缓存想要命中实现,则必须要将上一次sqlSession commit之后才能生效,不然将不会命中,原因:&br&两个不同的session必须提交前面一个session才能缓存生效的原因是因为mybatis的缓存会被一个transactioncache类包装住,所有的cache.putObject全部都会被暂时存到一个map里,等事务提交以后,这个map里的缓存对象才会被真正的cache类执行putObject操作。&br&&br&这么设计的原因是为了防止事务执行过程中出异常导致回滚,如果get到object后直接put进缓存,万一发生回滚,就很容易导致mybatis缓存被脏读
http://my.oschina.net/KingPan/blog/280167#OSC_h1_1 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持。 1.缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。 2. 二级缓存与一级…
Hibernate与MyBatis&p&Hibernate 是当前最流行的O/R mapping框架,它出身于&a href=&///?target=http%3A//sf.net& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&sf.net&/span&&span class=&invisible&&&/span&&i class=&icon-external&&&/i&&/a&,现在已经成为Jboss的一部分。 Mybatis 是另外一种优秀的O/R mapping框架。目前属于apache的一个子项目。&/p&&p&MyBatis 参考资料官网:&a href=&///?target=http%3A//www.mybatis.org/core/zh/index.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&mybatis.org/core/zh/ind&/span&&span class=&invisible&&ex.html&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&/p&&p&Hibernate参考资料: &a href=&///?target=http%3A//docs.jboss.org/hibernate/core/3.6/reference/zh-CN/html_single/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&docs.jboss.org/hibernat&/span&&span class=&invisible&&e/core/3.6/reference/zh-CN/html_single/&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&/p&1.1 Hibernate 简介&p&Hibernate对数据库结构提供了较为完整的封装,Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate 提供的方法完成持久层操作。程序员甚至不需要对SQL 的熟练掌握, Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并调用JDBC 接口加以执行。&/p&1.2 MyBatis简介&p&iBATIS 的着力点,则在于POJO 与SQL之间的映射关系。然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。 相对Hibernate“O/R”而言,iBATIS 是一种“Sql Mapping”的ORM实现。&/p&第二章 开发对比开发速度&p&Hibernate的真正掌握要比Mybatis来得难些。Mybatis框架相对简单很容易上手,但也相对简陋些。个人觉得要用好Mybatis还是首先要先理解好Hibernate。&/p&开发社区&p&Hibernate 与Mybatis都是流行的持久层开发框架,但Hibernate开发社区相对多热闹些,支持的工具也多,更新也快,当前最高版本4.1.8。而Mybatis相对平静,工具较少,当前最高版本3.2。&/p&开发工作量&p&Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。&/p&&p&针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。&/p&第三章 系统调优对比Hibernate的调优方案&ol&&li&制定合理的缓存策略;&/li&&li&尽量使用延迟加载特性;&/li&&li&采用合理的Session管理机制;&/li&&li&使用批量抓取,设定合理的批处理参数(batch_size);&/li&&li&进行合理的O/R映射设计&/li&&/ol&Mybatis调优方案&p&MyBatis在Session方面和Hibernate的Session生命周期是一致的,同样需要合理的Session管理机制。MyBatis同样具有二级缓存机制。 MyBatis可以进行详细的SQL优化设计。&/p&SQL优化方面&p&Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。&/p&&p&Hibernate HQL语句的调优需要将SQL打印出来,而Hibernate的SQL被很多人嫌弃因为太丑了。MyBatis的SQL是自己手动写的所以调整方便。但Hibernate具有自己的日志统计。Mybatis本身不带日志统计,使用Log4j进行日志记录。&/p&扩展性方面&p&Hibernate与具体数据库的关联只需在XML文件中配置即可,所有的HQL语句与具体使用的数据库无关,移植性很好。MyBatis项目中所有的SQL语句都是依赖所用的数据库的,所以不同数据库类型的支持不好。&/p&第四章 对象管理与抓取策略对象管理&p&Hibernate 是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的 JDBC/SQL 持久层方案中需要管理 SQL 语句,Hibernate采用了更自然的面向对象的视角来持久化 Java 应用中的数据。&/p&&p&换句话说,使用 Hibernate 的开发者应该总是关注对象的状态(state),不必考虑 SQL 语句的执行。这部分细节已经由 Hibernate 掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。&/p&&p&而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理。&/p&抓取策略&p&Hibernate对实体关联对象的抓取有着良好的机制。对于每一个关联关系都可以详细地设置是否延迟加载,并且提供关联抓取、查询抓取、子查询抓取、批量抓取四种模式。 它是详细配置和处理的。&/p&&p&而Mybatis的延迟加载是全局配置的。&/p&第五章 缓存机制对比Hibernate缓存&p&Hibernate一级缓存是Session缓存,利用好一级缓存就需要对Session的生命周期进行管理好。建议在一个Action操作中使用一个Session。一级缓存需要对Session进行严格管理。&/p&&p&Hibernate二级缓存是SessionFactory级的缓存。 SessionFactory的缓存分为内置缓存和外置缓存。内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定SQL语句等),对于应用程序来说,它是只读的。外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备。二级缓存称为进程级缓存或SessionFactory级缓存,它可以被所有session共享,它的生命周期伴随着SessionFactory的生命周期存在和消亡。&/p&MyBatis缓存&p&MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis 3 中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。&/p&&p&默认情况下是没有开启缓存的,除了局部的 session 缓存,可以增强变现而且处理循环 依赖也是必须的。要开启二级缓存,你需要在你的 SQL 映射文件中添加一行:
&cache/&&/p&&p&字面上看就是这样。这个简单语句的效果如下:&/p&&ol&&li&映射语句文件中的所有 select 语句将会被缓存。&/li&&li&映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。&/li&&li&缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。&/li&&li&根据时间表(比如 no Flush Interval,没有刷新间隔), 缓存不会以任何时间顺序 来刷新。&/li&&li&缓存会存储列表集合或对象(无论查询方法返回什么)的 1024 个引用。&/li&&li&缓存会被视为是 read/write(可读/可写)的缓存,意味着对象检索不是共享的,而 且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。&/li&&/ol&&p&所有的这些属性都可以通过缓存元素的属性来修改。&/p&&p&比如: &cache
eviction=&FIFO&
flushInterval=&60000&
size=&512&
readOnly=&true&/&&/p&&p&这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。可用的收回策略有, 默认的是 LRU:&/p&&ol&&li&LRU – 最近最少使用的:移除最长时间不被使用的对象。&/li&&li&FIFO – 先进先出:按对象进入缓存的顺序来移除它们。&/li&&li&SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。&/li&&li&WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。&/li&&/ol&&p&flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。&/p&&p&size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是1024。&/p&&p&readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。&/p&相同点&p&Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。&/p&不同点&p&Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。&/p&&p&MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。&/p&两者比较&p&因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。&/p&&p&而MyBatis在这一方面,使用二级缓存时需要特别小心。如果不能完全确定数据更新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常运行带来很大的隐患。&/p&第六章 Hibernate与Mybatis对比总结两者相同点&ul&&li&Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。&/li&&li&Hibernate和MyBatis都支持JDBC和JTA事务处理。&/li&&/ul&Mybatis优势&ul&&li&MyBatis可以进行更为细致的SQL优化,可以减少查询字段。&/li&&li&MyBatis容易掌握,而Hibernate门槛较高。&/li&&/ul&Hibernate优势&ul&&li&Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。&/li&&li&Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。&/li&&li&Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。&/li&&li&Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。&/li&&/ul&他人总结&ul&&li&Hibernate功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。 &/li&&li&Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。 &/li&&li&iBATIS入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。 &/li&&li&iBATIS的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。&/li&&/ul&原文出处:&a href=&///?target=http%3A//blog.csdn.net/firejuly/article/details/8190229& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Hibernate与 MyBatis的比较&i class=&icon-external&&&/i&&/a&
第一章 Hibernate与MyBatisHibernate 是当前最流行的O/R mapping框架,它出身于,现在已经成为Jboss的一部分。 Mybatis 是另外一种优秀的O/R mapping框架。目前属于apache的一个子项目。MyBatis 参考资料官网:Hib…
&p&ORM有一个问题是,当你的需求从简单变成不太简单的时候,会因为ORM无法支持多出来的那部分,导致原有的东西也不能用ORM,然后整个数据层就要重写了。&/p&&br&&p&譬如说,分库分表啊、update if exists啊……&/p&&p&========================================&/p&&p&小项目用orm没问题,但是一个未来会变大的小项目用orm就是个问题了。所以我的建议是,除非你有确凿的证据认为,这个项目不会变大,那你才能用orm。&/p&
ORM有一个问题是,当你的需求从简单变成不太简单的时候,会因为ORM无法支持多出来的那部分,导致原有的东西也不能用ORM,然后整个数据层就要重写了。 譬如说,分库分表啊、update if exists啊……========================================小项目用orm没问…
1 先纠正下楼主一个观点:做java领域开发ssh没你想象中重要,从目前形势来看大部分项目都会用到Spring,至于Struts(Struts2)和Hibernate通常会有其它一些更适合的框架来代替&br&&br&2 我个人认为学习框架首页要明白,什么是框架,项目中引入框架的目的,引入框架后解决了什么问题。 框架就是针对项目中特点问题做出的一套抽象的复用工具来简化编程开发工作。 从楼主提问看还是学生,没有更多的项目经验,无法体验真实背景下spring的作用觉得spring相关文档很抽象,我建议楼主先做一个不用任何框架的web项目,做完了再找相关资料学习spring(SSH),这时候SSH不一定学的很精,不懂地方可以先跳过,可以先知道怎么应用, 然后用SSH再将这项目重做一遍,深度体会下用SSH和不用SSH的区别,这时候你就可以深刻体会SSH的精华。回头看一些之前不明白的知识点查看相应的手册就可以搞定
1 先纠正下楼主一个观点:做java领域开发ssh没你想象中重要,从目前形势来看大部分项目都会用到Spring,至于Struts(Struts2)和Hibernate通常会有其它一些更适合的框架来代替 2 我个人认为学习框架首页要明白,什么是框架,项目中引入框架的目的,引入框架后…
持久化的意思就是把数据找个不是内存的地方存起来,就算你的程序关掉了重新打开,还能读回来,目标不限于XML、二进制文件、数据库、写到服务器上etc。
持久化的意思就是把数据找个不是内存的地方存起来,就算你的程序关掉了重新打开,还能读回来,目标不限于XML、二进制文件、数据库、写到服务器上etc。
Laravel 不是这么玩的。&br&&br&app/Models/User.php:&br&&br&&div class=&highlight&&&pre&&code class=&language-php&&&span class=&cp&&&?php&/span&
&span class=&k&&namespace&/span& &span class=&nx&&App\Models&/span&&span class=&p&&;&/span&
&span class=&k&&use&/span& &span class=&nx&&Illuminate\Database\Eloquent\Model&/span&&span class=&p&&;&/span&
&span class=&k&&class&/span& &span class=&nc&&User&/span& &span class=&k&&extends&/span& &span class=&nx&&Model&/span&
&span class=&p&&{&/span&
&span class=&k&&public&/span& &span class=&k&&function&/span& &span class=&nf&&cars&/span&&span class=&p&&()&/span&
&span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&nv&&$this&/span&&span class=&o&&-&&/span&&span class=&na&&hasMany&/span&&span class=&p&&(&/span&&span class=&nx&&Car&/span&&span class=&o&&::&/span&&span class=&na&&class&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&br&app/Models/Car.php:&br&&br&&div class=&highlight&&&pre&&code class=&language-php&&&span class=&cp&&&?php&/span&
&span class=&k&&namespace&/span& &span class=&nx&&App\Models&/span&&span class=&p&&;&/span&
&span class=&k&&use&/span& &span class=&nx&&Illuminate\Database\Eloquent\Model&/span&&span class=&p&&;&/span&
&span class=&k&&class&/span& &span class=&nc&&Car&/span& &span class=&k&&extends&/span& &span class=&nx&&Model&/span&
&span class=&p&&{&/span&
&span class=&k&&public&/span& &span class=&k&&function&/span& &span class=&nf&&user&/span&&span class=&p&&()&/span&
&span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&nv&&$this&/span&&span class=&o&&-&&/span&&span class=&na&&belongsTo&/span&&span class=&p&&(&/span&&span class=&nx&&User&/span&&span class=&o&&::&/span&&span class=&na&&class&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&br&用户的所有车辆: &br&&br&&div class=&highlight&&&pre&&code class=&language-text&&$cars = User::find(1)-&
&/code&&/pre&&/div&&br&取车的主人&br&&br&&div class=&highlight&&&pre&&code class=&language-text&&$owner = Car::find(1)-&
dd($owner-&toArray());
&/code&&/pre&&/div&
Laravel 不是这么玩的。 app/Models/User.php: &?php
namespace App\M
use Illuminate\Database\Eloquent\M
class User extends Model
public function cars()
return $this-&hasMany(Car::class);
app/Models/Car.php: &?php
序列化可以将一个复杂的对象转化为一维的数据,而这为持久化提供了很大的方便,因为文件就是一维的,将一维的东西写入文件自然比较方便。&br&&br&不过持久化是个很宽泛的概念,可以是写入文件,也可以是存入数据库,写入注册表等多种方式。其本意是延长对象或数据的生命周期,让其可以超越程序的生命周期,程序关闭了,甚至服务器关机了,下次运行程序时又可以让对象或数据恢复到原来的状态。&br&&br&而序列化也不一定是用来持久化的,可以是用来传递使用,如从计算机A传递到计算机B;也可以用来进行深拷贝;总之序列化主要解决从复杂的数据结构转化为一维结构,或者从一维结构从新构建复杂的数据结构。
序列化可以将一个复杂的对象转化为一维的数据,而这为持久化提供了很大的方便,因为文件就是一维的,将一维的东西写入文件自然比较方便。 不过持久化是个很宽泛的概念,可以是写入文件,也可以是存入数据库,写入注册表等多种方式。其本意是延长对象或数据…
实际项目开发时,选择一个工具,有如下考量:&br&&ol&&li&是否能够解决实际问题;对于 Hibernate 来说,完成实体和表之间的映射,是其主要功能,其他功能都可以按需选择,并不是说,这个工具有什么功能,就都必须用上,工具的使用向来都是跟着问题走的。&/li&&li&时间成本;面对紧张的时间安排,如果项目组所有成员都要学习 Hibernate 到精通,显然是很浪费时间的,而且 Hibernate 也不是看看视频看看书就可以看到实际运用场景的,实际开发中,很多使用 Hibernate 一两年的人也不是很清楚该怎么使用它提供的高级功能,也没时间和心思去翻官方 manual,那么,大家就会想:这个工具大家都不是很熟练,也没有十足的把握用好,那就只能把它最基本的功能用好算了,也就是,撇开那些高级特性,先用基本功能把活干了再说。&/li&&li&性能;Hibernate 的性能一直饱受诟病,通用工具都难免此类问题,实体加的关联多了,数据加载的就慢,再者,Hibernate 最擅长的并非查询,而是写操作,毕竟是全字段查询,相对来说,JdbcTemplate 就可以指定查询具体哪些字段,自己指定的关联查询 SQL 也比 Hibernate 生成的 SQL 高效简洁,让 JdbcTemplate 负责查询,Hibernate 负责写入,是个不错的搭配。&/li&&li&可维护性;实体关联需要维护,还得控制数据的加载时机(懒加载)、单/双向关系、级联以及抓取策略等,稍微配置不当,就会出现异常,这样的话,与其使用高级功能带来这么多问题,索性干脆不用,省得以后麻烦。&/li&&li&依赖性;项目开发要以数据为核心,数据库修改要灵活轻便,而不依赖于上层工具(如 Hibernate),如果实体添加了太多关联,日后使用其他映射工具或者修改数据库,这些实体就出现问题了,需要对应的修改,毕竟,不是所有工具都像 Hibernate 一样站在对象的角度思考问题的,例如:JOOQ 就提倡 SQL 的使用,反对所有操作都使用 ORM。&/li&&/ol&总之,一句话,开发团队总会选择工具最快最灵活的一面,摒弃他们认为不好的一面。&br&如上,暂时想到这些。&br&&br&&b&我的其他回答:&/b&&br&&ul&&li&&a href=&/question//answer/& class=&internal&&spring有什么缺点吗? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&哪些企业或项目在用Spring boot,或者它会在多大程度上替代Spring? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&会计转行从事IT,如何在一年时间内全职学习? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&SpringDataJPA持久层问题? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&spring4+hibernate4 事务管理 非常难受的问题 ? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&spring 中为何存在import注解,同一个包中的类直接使用就行了 用import注解感觉有点怪? - Night Silent 的回答&/a&&br&&/li&&li&更多回答,请关注我,获取最新动态&/li&&li&如果此回答帮到了你,一个小小的赞,一次分享,都会让更多人受益&/li&&/ul&&br&此外,有兴趣的话,欢迎加入我的 &b&Java EE 自学群&/b&&br&&ul&&li&&b&一号群:(即将满额)&/b&:&a href=&///?target=http%3A///cgi-bin/qm/qr%3Fk%3DO_AAjKe3irM0TY6ayvKIrvtvEMNk9rTT& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&二维码页面&i class=&icon-external&&&/i&&/a& (二维码自动识别)&br&&/li&&li&二号群:(新群,限时免费加入): &a href=&///?target=http%3A///cgi-bin/qm/qr%3Fk%3DWUu4I0-EtyXlUysdvJ1juYlFiFnZY9wQ& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&二维码页面&i class=&icon-external&&&/i&&/a& (二维码自动识别)&br&&br&&/li&&/ul&如果觉得我的回答对你很有帮助,可以考虑微信打赏:&br&&img src=&/025e07ad951d056f189e56de1a44bebc_b.png& data-rawwidth=&264& data-rawheight=&238& class=&content_image& width=&264&&
实际项目开发时,选择一个工具,有如下考量: 是否能够解决实际问题;对于 Hibernate 来说,完成实体和表之间的映射,是其主要功能,其他功能都可以按需选择,并不是说,这个工具有什么功能,就都必须用上,工具的使用向来都是跟着问题走的。时间成本;面对…
使用 ORM 的好处:&br&&br&1. 避免裸写 SQL 语句,一个是看起来简洁,另一个是借助 ORM 框架防止 SQL 注入&br&&br&2. 将 Data 抽象为 Object,由此可以融入现有的 OO 编程方法&br&&br&缺点:&br&&br&1. 据说 ORM 性能不行&br&&br&不过以我自身的姿势水平,还没到考虑 ORM 对性能消耗的地步,另外从周围前辈们的经验来看,基本也都推荐使用 ORM 作为最佳实践
使用 ORM 的好处: 1. 避免裸写 SQL 语句,一个是看起来简洁,另一个是借助 ORM 框架防止 SQL 注入 2. 将 Data 抽象为 Object,由此可以融入现有的 OO 编程方法 缺点: 1. 据说 ORM 性能不行 不过以我自身的姿势水平,还没到考虑 ORM 对性能消耗的地步,另…
相比裸 sql 的话,能想到使用 orm 的好处主要是:&br&&ul&&li&默认的防注入,使用裸 sql 配合一些规范也可以避免注入,但是一旦不遵循规范仍是危险的;&/li&&li&查询条件的动态构造,比如我想根据用户的不同参数来组合不同的查询,使用 orm 只要在 query 对象里追加条件就可以,然而交给裸 sql 几乎不可能干净又安全地做到;&/li&&li&容易插钩子集成自动的缓存失效(不过个人没在线上见过);&/li&&/ul&听到过的反对使用 orm 的意见似乎主要在于:&br&&ul&&li&开发者不能明确 sql 的内容,使 dba 有时候不好办,反观有限数量的裸 sql,dba 很容易 review;&br&&/li&&/ul&个人倾向于这不算 orm 的锅,开发者在使用 orm 构造查询时应该理解 query 的内容,dba 也有自己的方法和流程去了解系统中存在的 query。
相比裸 sql 的话,能想到使用 orm 的好处主要是: 默认的防注入,使用裸 sql 配合一些规范也可以避免注入,但是一旦不遵循规范仍是危险的;查询条件的动态构造,比如我想根据用户的不同参数来组合不同的查询,使用 orm 只要在 query 对象里追加条件就可以,…
你需要的不是确保同一张表的SQL操作顺序,而是保证同一个客户发来的SQL请求按顺序执行。
你需要的不是确保同一张表的SQL操作顺序,而是保证同一个客户发来的SQL请求按顺序执行。
回答这个问题之前,首先让我们回顾一下,一个关系数据库中都有什么?没错,简单来说,就是一张张表。表中又有什么?行和列,一行就是一条记录,一列就代表着一条记录的某个属性。举例来说,一个学籍数据库可能包含一张学生信息表,表中每行记录着一个学生的信息,由很多列组成,每一列表示学生的一个属性,比如姓名、年龄、入学时间……&br&有没有觉得和python中的类、实例对象以及成员属性的概念有某种映射关系呢?哈,没错,orm其实就是把表映射成了类,它包含一些成员属性,相当于一个模板,通过这个模板,我们给相应的属性填上一个值,可以创建一个实例对象也就是一条记录。然后把常用的一些SQL操作封装成对应的方法,比如select封装为get方法,这样就实现了一个orm。&br&当然,如果要自己写一个orm,技术层面上,你还需要去理解什么是元类、如何使用元类,以及一些有关描述器的知识。&br&&br&手机党,不方便打字,就说这些了。更多的内容,题主可以自行google,也可以在github上找一些其他人实现的轻量级orm看一看
回答这个问题之前,首先让我们回顾一下,一个关系数据库中都有什么?没错,简单来说,就是一张张表。表中又有什么?行和列,一行就是一条记录,一列就代表着一条记录的某个属性。举例来说,一个学籍数据库可能包含一张学生信息表,表中每行记录着一个学生的…
数据的“持久化”(Persistence) 和算法里面的“可持久化”(Persistent) 是不同的概念&br&&br&你看他们词性都不同怎么可能会一样嘛&br&&br&前者你可以认为是保存,大概的感觉是你看内存里面的东西掉个电就没了一点也不持久。硬盘里的东西看起来就持久多了。&br&&br&后者的概念我想你应该很清楚了吧,把每一个历史时刻都记录下来供操作使用。
数据的“持久化”(Persistence) 和算法里面的“可持久化”(Persistent) 是不同的概念 你看他们词性都不同怎么可能会一样嘛 前者你可以认为是保存,大概的感觉是你看内存里面的东西掉个电就没了一点也不持久。硬盘里的东西看起来就持久多了。 后者的概念…
&b&开源技术一旦涉及整合,就会互相影响,Spring 和 Hibernate 是个典型。&/b&&br&&br&&b&鉴于 hibernate 实现了 JPA 规范,就不再赘述 JpaDaoSupport、JpaTemplate&/b&&br&&b&下面以 HibernateDaoSupport、HibernateTemplate 为例同时解释。&/b&&br&&br&Spring 提供 HibernateDaoSupport、HibernateTemplate 的初衷是:&br&&ul&&li&提供 common dao operation method (通用数据操作方法),方便快速开发&/li&&ul&&li&你的 dao 可以 extends xxxDaoSupport 获取继承来的便利方法&/li&&li&你的 dao 可以 autowire xxxTemplate 获取注入来的便利方法&/li&&li&以上两种方式本质是相同的&/li&&/ul&&li&管理 hibernate 的 session&/li&&ul&&li&hibernate 3.0.1 之前,并没有提供会话管理方案,所以 &/li&&ul&&li&Spring 不得已在 HibernateDaoSupport、HibernateTemplate 中提供了支持&/li&&li&通过 HibernateDaoSupport、HibernateTemplate 获取到的 session,可以无缝绑定 spring 管理的事务&/li&&/ul&&/ul&&li&对持久层异常自动转化&/li&&ul&&li&虽然 hibernate 将底层异常封装为 HibernateException 实现了大一统,但 Spring 显然是更希望将任何持久层异常(不单单限定于 HibernateException)封装为自己的 DataAccessException 实现大一统&/li&&/ul&&/ul&&b&但是,以上,在 hibernate 3.0.1 出现后,都成了历史。&/b&&br&&br&不负众望,hibernate 在 3.0.1 后实现了&a href=&///?target=https%3A//docs.jboss.org/hibernate/orm/3.3/reference/en/html/architecture.html%23architecture-current-session& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&会话管理&i class=&icon-external&&&/i&&/a&(contextual session),对应地,Spring 在 HibernateDaoSupport、HibernateTemplate 的 javadoc 中也做了如下更新:&br&&img src=&/ac67c34ca929b13853ad_b.png& data-rawwidth=&1073& data-rawheight=&582& class=&origin_image zh-lightbox-thumb& width=&1073& data-original=&/ac67c34ca929b13853ad_r.png&&&br&Spring Reference 中也声明如下:&br&&img src=&/f06db9e775544_b.png& data-rawwidth=&1245& data-rawheight=&362& class=&origin_image zh-lightbox-thumb& width=&1245& data-original=&/f06db9e775544_r.png&&&br&&b&总结一下&/b&,如果使用的是 Hibernate 3.0.1+,现在 Spring 推荐这么做:&br&&ul&&li&Dao 不要再继承 HibernateDaoSupport 或注入 HibernateTemplate,这两个类都已不推荐使用&/li&&li&Dao 应该直接注入 Hibernate 的 SessionFactory&/li&&/ul&这么做的好处是:&br&&ul&&li&Dao 层代码仅依赖于 hibernate api, 但不依赖于 spring api,这样更合理,毕竟 hibernate 才是持久层功能的提供者&/li&&li&Dao 内可以通过 SessionFactory.getCurrentSession() 来进行纯 hibernate 操作,获取到的 Session 也是受管理的(managed),至于管理方案,可以通过如下方式进行配置&/li&&ul&&li&先配置 hibernate ,然后整合到 spring 配置里&/li&&/ul&&/ul&&b&hibernate.cfg.xml&/b&&br&&div class=&highlight&&&pre&&code class=&language-xml&&&span class=&nt&&&hibernate-configuration&&/span&
&span class=&nt&&&session-factory&&/span&
&span class=&c&&&!-- ... --&&/span&
&span class=&c&&&!-- Enable Hibernate's automatic session context management --&&/span&
&span class=&nt&&&property&/span& &span class=&na&&name=&/span&&span class=&s&&&current_session_context_class&&/span&&span class=&nt&&&&/span&thread&span class=&nt&&&/property&&/span&
&span class=&nt&&&/session-factory&&/span&
&span class=&nt&&&/hibernate-configuration&&/span&
&/code&&/pre&&/div&&b&applicationContext.xml&/b&&br&&div class=&highlight&&&pre&&code class=&language-xml&&&span class=&nt&&&bean&/span& &span class=&na&&class=&/span&&span class=&s&&&org.springframework.orm.hibernate3.LocalSessionFactoryBean&&/span&
&span class=&na&&id=&/span&&span class=&s&&&sessionFactory&&/span&&span class=&nt&&&&/span&
&span class=&nt&&&property&/span& &span class=&na&&name=&/span&&span class=&s&&&configLocation&&/span&&span class=&nt&&&&/span&
&span class=&nt&&&value&&/span&classpath:hibernate.cfg.xml&span class=&nt&&&/value&&/span&
&span class=&nt&&&/property&&/span&
&span class=&nt&&&/bean&&/span&
&/code&&/pre&&/div&&br&&ul&&ul&&li&直接配置 Spring 提供的 LocalSessionFactoryBean&/li&&/ul&&/ul&&div class=&highlight&&&pre&&code class=&language-xml&&&span class=&nt&&&bean&/span&
&span class=&na&&id=&/span&&span class=&s&&&sessionFactory&&/span&
&span class=&na&&class=&/span&&span class=&s&&&org.springframework.orm.hibernate4.LocalSessionFactoryBean&&/span& &span class=&nt&&&&/span&
&span class=&nt&&&property&/span& &span class=&na&&name=&/span&&span class=&s&&&hibernateProperties&&/span& &span class=&nt&&&&/span&
&span class=&nt&&&props&&/span&
&span class=&nt&&&prop&/span& &span class=&na&&key=&/span&&span class=&s&&&hibernate.show_sql&&/span&&span class=&nt&&&&/span&true&span class=&nt&&&/prop&&/span&
&span class=&nt&&&prop&/span& &span class=&na&&key=&/span&&span class=&s&&&hibernate.current_session_context_class&&/span&&span class=&nt&&&&/span&thread&span class=&nt&&&/prop&&/span&
&span class=&nt&&&/props&&/span&
&span class=&nt&&&/property&&/span&
&span class=&nt&&&/bean&&/span&
&/code&&/pre&&/div&&br&&b&回到正题,说下题主的问题&/b&&br&&ul&&li&使用 JpaDaoSupport 需要什么jar包?&/li&&/ul&开源技术的整合,依赖问题比较严重,建议使用 maven 进行管理,参考依赖如下:&br&&div class=&highlight&&&pre&&code class=&language-xml&&&span class=&c&&&!--使用 hibernate 实现 JPA--&&/span&
&span class=&nt&&&dependency&&/span&
&span class=&nt&&&groupId&&/span&org.hibernate&span class=&nt&&&/groupId&&/span&
&span class=&nt&&&artifactId&&/span&hibernate-entitymanager&span class=&nt&&&/artifactId&&/span&
&span class=&nt&&&version&&/span&${hibernate.version}&span class=&nt&&&/version&&/span&
&span class=&nt&&&/dependency&&/span&
&span class=&c&&&!--spring 相关依赖--&&/span&
&span class=&nt&&&dependency&&/span&
&span class=&nt&&&groupId&&/span&org.springframework&span class=&nt&&&/groupId&&/span&
&span class=&nt&&&artifactId&&/span&spring-orm&span class=&nt&&&/artifactId&&/span&
&span class=&nt&&&version&&/span&${spring.version}&span class=&nt&&&/version&&/span&
&span class=&nt&&&/dependency&&/span&
&/code&&/pre&&/div&&br&&ul&&li&JpaDaoSupport 和 jdbcDaoSupport 的用法有什么区别&/li&&ul&&li&使用方式&/li&&ul&&li&Spring 提供的 xxxDaoSupport 都是需要&b&继承&/b&来使用的&/li&&li&Spring 提供的 xxxTemplate 都是需要&b&注入&/b&来使用的&/li&&li&xxxDaoSupport、xxxTemplate 本质相同,建议看 xxxDaoSupport 源码&br&&/li&&li&一般来说,组合(注入)优先于继承,即便要用,注入使用比较好&/li&&/ul&&li&使用区别&/li&&ul&&li&JpaDaoSupport 基于 JPA,jdbcDaoSupport 基于 JDBC,用法没有可比性。&br&&/li&&/ul&&/ul&&/ul&&br&&b&书籍推荐&/b&&br&&ul&&li&JPA&/li&&ul&&li&参考书:《Java Persistence with JPA - Daoqi Yang》&/li&&li&搭配 &a href=&///?target=http%3A//docs.jboss.org/hibernate/orm/4.2/manual/en-US/html_single/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Hibernate Manual&i class=&icon-external&&&/i&&/a& 做参照&/li&&/ul&&/ul&&img src=&/cb31ddd69ad1b0c4d63fcf2c1038ded0_b.png& data-rawwidth=&1315& data-rawheight=&487& class=&origin_image zh-lightbox-thumb& width=&1315& data-original=&/cb31ddd69ad1b0c4d63fcf2c1038ded0_r.png&&&br&&ul&&li&JDBC + Spring&/li&&ul&&li&参考书:《Just.Spring.Data.Access - Madhusudhan.Konda》&/li&&li&搭配 Spring Reference - &a href=&///?target=https%3A//docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&18. Data access with JDBC&i class=&icon-external&&&/i&&/a&&br&&/li&&/ul&&/ul&&img src=&/a346f373bdc63af69ee55b5_b.png& data-rawwidth=&1273& data-rawheight=&492& class=&origin_image zh-lightbox-thumb& width=&1273& data-original=&/a346f373bdc63af69ee55b5_r.png&&&br&以上,暂时这么多,想到再补充。&br&&br&&b&参考资料:&/b&&br&&ul&&li&&a href=&///?target=http%3A//static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/orm.html%23orm-hibernate-straight& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Spring Reference
- 13.3.2 Implementing DAOs based on plain Hibernate 3 API&i class=&icon-external&&&/i&&/a&&/li&&li&&a href=&///?target=https%3A//docs.jboss.org/hibernate/orm/3.3/reference/en/html/architecture.html%23architecture-current-session& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Hibernate Manual - 2.5 Contexual Session&i class=&icon-external&&&/i&&/a&&/li&&/ul&&br&&ul&&b&我的其他回答:&/b&&br&&li&&a href=&/question//answer/& class=&internal&&spring有什么缺点吗? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&哪些企业或项目在用Spring boot,或者它会在多大程度上替代Spring? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&会计转行从事IT,如何在一年时间内全职学习? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&SpringDataJPA持久层问题? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&spring4+hibernate4 事务管理 非常难受的问题 ? - Night Silent 的回答&/a&&br&&/li&&li&&a href=&/question//answer/& class=&internal&&spring 中为何存在import注解,同一个包中的类直接使用就行了 用import注解感觉有点怪? - Night Silent 的回答&/a&&br&&/li&&li&更多回答,请关注我,获取最新动态&br&&/li&&li&如果此回答帮到了你,一个小小的赞,一次分享,都会让更多人受益&br&&/li&&br&此外,有兴趣的话,欢迎加入我的 &b&Java EE 自学群&/b&&br&&li&&b&一号群:(即将满额)&/b&:&a href=&///?target=http%3A///cgi-bin/qm/qr%3Fk%3DO_AAjKe3irM0TY6ayvKIrvtvEMNk9rTT& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&二维码页面&i class=&icon-external&&&/i&&/a& (二维码自动识别)&br&&/li&&li&二号群:(新群,限时免费加入): &a href=&///?target=http%3A///cgi-bin/qm/qr%3Fk%3DWUu4I0-EtyXlUysdvJ1juYlFiFnZY9wQ& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&二维码页面&i class=&icon-external&&&/i&&/a& (二维码自动识别)&br&&/li&如果觉得我的回答对你很有帮助,可以考虑微信打赏:&br&&img src=&/025e07ad951d056f189e56de1a44bebc_b.png& data-rawwidth=&264& data-rawheight=&238& class=&content_image& width=&264&&&/ul&&b&&br&&br&关于群的说明:&/b&&br&&ul&&li&长期以来,我创建的自学群饱受各种&b&培训机构、群宣水军、拿来主义者&/b&侵扰,为保持本群的技术氛围,本群入群方式修改为&b&付费入群&/b&&br&&/li&&li&已经在群内的各位成员,请珍惜这个平台,一旦违反群规总是讨论和 Java 无关话题的,将被清理出群,再次进群,你只能付费,不守规矩是有代价的&br&&/li&&li&新入群的朋友,请先查阅群公告,了解下群规,入群后,欢迎有准备的提问,拒绝拿来主义&br&&/li&&li&入群所需费用,会被充当群费&br&&/li&&li&如果有朋友觉得&b&本群/本篇文章&/b&帮到了你,也可以联系我(Q或知乎私信),为本群捐赠群费,我会在公告里向大家公示数额及用途&br&&/li&&li&群费用途:为大家合购教程、为群续费、由我牵头做一些特定的事情(投票决定)等等&br&&/li&&li&再次重申:培训机构、群宣水军、拿来主义者,请自觉远离&/li&&/ul&
开源技术一旦涉及整合,就会互相影响,Spring 和 Hibernate 是个典型。 鉴于 hibernate 实现了 JPA 规范,就不再赘述 JpaDaoSupport、JpaTemplate 下面以 HibernateDaoSupport、HibernateTemplate 为例同时解释。 Spring 提供 HibernateDaoSupport、Hiberna…
SSH(Struts,Spring,Hibernate)是一种常用的Web开发的框架组合,其中Spring作为Ioc容器负责组装,Struts作为前端框架负责展示层逻辑(MVC),Hibernate负责数据的持久化。这三者都是开源框架,也是各自领域中有代表性的框架,三者结合起来是一种最佳实践。&br&&br&而REST是一个C/S(包含B/S)的 软件的架构模式,前端的C(或B)应该以什么样的方式,特别是在HTTP协议上通讯时,和后端的S打交道,形成清晰、容易理解的的交互。由于基于HTTP协议,因此服务端的程序通常跑在Web服务器上,但不一定是以Web方式展现的应用程序。&br&&br&使用SSH框架时,可以依循REST架构模式,以使软件有良好的架构。但是REST不限于 Web开发,特别是在网络服务的API方面,REST已经成为一种事实的标准,可以和Web Service协议栈一争高下。&br&&br&
SSH(Struts,Spring,Hibernate)是一种常用的Web开发的框架组合,其中Spring作为Ioc容器负责组装,Struts作为前端框架负责展示层逻辑(MVC),Hibernate负责数据的持久化。这三者都是开源框架,也是各自领域中有代表性的框架,三者结合起来是一种最佳实践…
&p&真正好的做法,还是全部SQL封装成Stored Procedure,然后只给应用服务器开放Execute权限,有效防止各种问题。好处我都说过几千遍了。&/p&&br&&p&再说了,很多时候SQL是跟数据库的schema棒死在一起的。你为什么要把两个强关联的东西分散在不同的地方来写?这简直太没法理解了。&/p&&br&&p&所以Jinq没必要用,因为你一旦用了,证明你的设计有问题。我对Entity Framework的态度也差不多。我自己也只用Linq来做SQL以外的事情。&/p&
真正好的做法,还是全部SQL封装成Stored Procedure,然后只给应用服务器开放Execute权限,有效防止各种问题。好处我都说过几千遍了。 再说了,很多时候SQL是跟数据库的schema棒死在一起的。你为什么要把两个强关联的东西分散在不同的地方来写?这简直太没法…
已有帐号?
无法登录?
社交帐号登录

我要回帖

更多关于 编写小学生做加减乘除 的文章

 

随机推荐