P18

  hibernate4实战 之第六部分 文档

Hibernate4实战之第六部分:基本实现原理2013-05-1101:35:00标签:HYPERLINK"http://blog.51cto.com/tag-%E6%95%B0%E6%8D%AE%E5%BA%93.html"\t"_blank"数据库HYPERLINK"http://blog.51cto.com/tag-SQL.html"\t"_blank"SQLHYPERLINK"http://blog.51cto.com/tag-%E5%AF%B9%E8%B1%A1.html"\t"_blank"对象HYPERLINK"http://blog.51cto.com/tag-Hibernate.html"\t"_blank"HibernateHYPERLINK"http://blog.51cto.com/tag-%E8%A1%8C%E4%B8%9A%E6%95%B0%E6%8D%AE.html"\t"_blank"行业数据HYPERLINK"http://blog.51cto.com/zt/617"\t"_blank"INCLUDEPICTURE"http://3001448.blog.51cto.com/image/zt/big.png"\*MERGEFORMATINET原创作品,允许转载,转载时请务必以超链接形式标明文章HYPERLINK"http://3001448.blog.51cto.com/2991448/1205813"\t"_blank"原始出处、作者信息和本声明。否则将追究法律责任。HYPERLINK"http://3001448.blog.51cto.com/2991448/1205813"http://3001448.blog.51cto.com/2991448/1205813整体流程1:通过configuration来读cfg.xml文件2:得到SessionFactory工厂3:通过SessionFactory工厂来创建Session实例4:通过Session打开事务5:通过session的api操作数据库6:事务提交7:关闭连接 说明:以下分方法描述的实现流程并不是Hibernate的完整实现流程,也不是Hibernate的完整实现顺序,只是描述了Hibernate实现这些方法的主干和基本方式,主要是用来理解这些方法背后都发生了些什么,如果需要详细完整的实现流程,请查阅Hibernate相应文档和源代码INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/22/85496e48dbd61a7c31baa95771128a94__1.bmp"\*MERGEFORMATINET 当我们调用了session.save(UserModel)后:1:TO--->PO:Hibernate先在缓存中查找,如果发现在内部缓存中已经存在相同id的PO,就认为这个数据已经保存了,抛出例外。如果缓存中没有,Hibernate会把传入的这个TO对象放到session控制的实例池去,也就是把一个瞬时对象变成了一个持久化对象。如果需要Hibernate生成主键值,Hibernate就会去生成id并设置到PO上2:客户端提交事务或者刷新内存3:根据model类型和cfg.xml中映射文件的注册来找到相应的hbm.xml文件4:根据hbm.xml文件和model来动态的拼sql,如下:insertinto表名(来自hbm.xml)(字段名列表(来自hbm.xml))values(对应的值的列表(根据hbm.xml从传入的model中获取值))5:真正用JDBC执行sql,把值添加到数据库6:返回这个PO的id。INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/22/b41cef57e703ae3c9f920ecd1433a63d__2.bmp"\*MERGEFORMATINET INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/22/9457a21896d91dab8bfa15f1ee733648__3.bmp"\*MERGEFORMATINET当我们调用了session.update(UserModel)后:1:DO--->PO:首先根据model的主键在hibernate的实例池中查找该对象,找到就抛出错误。如果没有就DO--->PO,Hibernate会把传入的这个DO对象放到session控制的实例池去,也就是把一个瞬时对象变成了一个持久化对象2:客户端提交事务或者刷新内存

netfjfzlj 2016-03-14   685   0
P3

  hibernate4实战 之第五部分:hibernate的事务和并发 文档

Hibernate4实战之第五部分:Hibernate的事务和并发2013-05-1101:34:00标签:HYPERLINK"http://blog.51cto.com/tag-Hibernate.html"\t"_blank"HibernateHYPERLINK"http://blog.51cto.com/tag-%E4%BA%8B%E5%8A%A1.html"\t"_blank"事务HYPERLINK"http://blog.51cto.com/tag-%E5%B9%B6%E5%8F%91.html"\t"_blank"并发HYPERLINK"http://blog.51cto.com/tag-%E6%95%B0%E6%8D%AE%E5%BA%93.html"\t"_blank"数据库HYPERLINK"http://blog.51cto.com/tag-%E5%BA%94%E7%94%A8.html"\t"_blank"应用HYPERLINK"http://blog.51cto.com/zt/617"\t"_blank"INCLUDEPICTURE"http://3001448.blog.51cto.com/image/zt/big.png"\*MERGEFORMATINET原创作品,允许转载,转载时请务必以超链接形式标明文章HYPERLINK"http://3001448.blog.51cto.com/2991448/1205814"\t"_blank"原始出处、作者信息和本声明。否则将追究法律责任。HYPERLINK"http://3001448.blog.51cto.com/2991448/1205814"http://3001448.blog.51cto.com/2991448/1205814Hibernate本身没有事务的实现Hibernate直接使用JDBC连接和JTA资源,不添加任何附加锁定行为。也就是说你在Hibernate里面使用的事务要么是JDBC的事务,要么是JTA的事务。Hibernate不锁定内存中的对象你的应用程序会按照你的数据库事务的隔离级别规定的那样运作,真正对事务的实现和支持也依赖于数据库。 对于并发处理,Hibernate提供了乐观锁和悲观锁来进行并发处理Hibernate对自动乐观并发控制提供版本管理,针对行级悲观锁定,Hibernate也提供了辅助的(较小的)API,它使用了SELECTFORUPDATE的SQL语法Hibernate的Session是和事务联系在一起的可以通过Session去获取事务的接口,从而进行事务的控制。 数据库事务应该尽可能的短这样能降低数据库中的锁争用。数据库长事务会阻止你的应用程序扩展到高的并发负载。因此,假若在用户思考期间让数据库事务开着,直到整个工作单元完成才关闭这个事务,这绝不是一个好的设计。这就引出一个问题:一个操作单元,也就是一个事务单元的范围应该是多大?一个操作一个?一个请求一个?一个应用一个? 反模式:session-per-operation在单个线程中,不要因为一次简单的数据库调用,就打开和关闭一次Session!数据库事务也是如此。也就是说应该禁止自动事务提交(auto-commit)。 session-per-request最常用的模式是每个请求一个会话。在这种模式下,来自客户端的请求被发送到服务器端,即Hibernate持久化层运行的地方,一个新的HibernateSession被打开,并且执行这个操作单元中所有的数据库操作。一旦操作完成(同时对客户端的响应也准备就绪),session被同步,然后关闭。会话和请求之间的关系是一对一的关系。Hibernate内置了对“当前session(currentsession)”的管理,用于简化此模式。你要做的一切就是在服务器端要处理请求的时候,开启事务,在响应发送给客户之前结束事务,通常使用ServeltFilter来完成。 非托管环境下所谓非托管,指的是:应用程序没有托管到J2EE环境中,通常由Hibernate自己来负责管理数据库连接池。应用程序开发人员必须手工设置事务声明,换句话说,就是手工启动,提交,或者回滚数据库事务。 使用JTA又有两种方式,一种是在Hibernate配置里面修改transaction的factory类,从而在程序里面可以直接使用Hibernate的事务API,也就是程序不用变化。另外一种方式就是直接通过JNDI去查找UserTransaction,然后直接在程序里面使用JTA的接口来控制事务。应用程序级别的版本检查简单点说,就是由应用程序自己实现版本检查来确保对话事务的隔离,从数据访问的角度来说是最低效

netfjfzlj 2016-03-14   468   0
P3

  hibernate4实战 之第七部分 文档

Hibernate4实战之第七部分:最佳实践2013-05-1101:36:00标签:HYPERLINK"http://blog.51cto.com/tag-Hibernate4%E5%AE%9E%E6%88%98%E4%B9%8B%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5.html"\t"_blank"Hibernate4实战之最佳实践HYPERLINK"http://blog.51cto.com/zt/617"\t"_blank"INCLUDEPICTURE"http://3001448.blog.51cto.com/image/zt/big.png"\*MERGEFORMATINET原创作品,允许转载,转载时请务必以超链接形式标明文章HYPERLINK"http://3001448.blog.51cto.com/2991448/1205812"\t"_blank"原始出处、作者信息和本声明。否则将追究法律责任。HYPERLINK"http://3001448.blog.51cto.com/2991448/1205812"http://3001448.blog.51cto.com/2991448/1205812设计细颗粒度的持久类并且使用<component>来实现映射。例如使用一个Address持久类来封装street,suburb,state,postcode.这将有利于代码重用和简化代码重构(refactoring)的工作。对持久类声明标识符属性(identifierproperties)。Hibernate中标识符属性是可选的,不过有很多原因来说明你应该使用标识符属性。我们建议标识符应该是“人造”的(自动生成,不涉及业务含义)。使用自然键(naturalkeys)标识对所有的实体都标识出自然键,用<natural-id>进行映射。实现equals()和hashCode(),在其中用组成自然键的属性进行比较。为每个持久类写一个映射文件不要把所有的持久类映射都写到一个大文件中。把com.eg.Foo映射到com/eg/Foo.hbm.xml中,在团队开发环境中,这一点显得特别有意义。把映射文件作为资源加载把映射文件和他们的映射类放在一起进行部署。考虑把查询字符串放在程序外面如果你的查询中调用了非ANSI标准的SQL函数,那么这条实践经验对你适用。把查询字符串放在映射文件中可以让程序具有更好的可移植性。使用绑定变量就像在JDBC编程中一样,应该总是用占位符"?"来替换非常量值,不要在查询中用字符串值来构造非常量值!更好的办法是在查询中使用命名参数。不要自己来管理JDBCconnectionsHibernate允许应用程序自己来管理JDBCconnections,但是应该作为最后没有办法的办法。如果你不能使用Hibernate内建的connectionsproviders,那么考虑实现自己来实现org.hibernate.connection.ConnectionProvider考虑使用用户自定义类型(customtype)假设你有一个Java类型,来自某些类库,需要被持久化,但是该类没有提供映射操作需要的存取方法。那么你应该考虑实现org.hibernate.UserType接口。这种办法使程序代码写起来更加自如,不再需要考虑类与Hibernatetype之间的相互转换。 在性能瓶颈的地方使用硬编码的JDBC在系统中对性能要求很严格的一些部分,某些操作也许直接使用JDBC会更好。但是请先确认这的确是一个瓶颈,并且不要想当然认为JDBC一定会更快。如果确实需要直接使用JDBC,那么最好打开一个HibernateSession然后从Session获得connection,按照这种办法你仍然可以使用同样的transaction策略和底层的connectionprovider。理解Session清洗(flushing)Session会不时的向数据库同步持久化状态,如果这种操作进行的过于频繁,性能会受到一定的影响。有时候你可以通过禁止自动flushing,尽量最小化非必要的flushing操作,或者更进一步,在一个特定的transaction中改变查询和其它操作的顺序。在三层结构中,考虑使用托管对象(detachedobject)当使用一个servlet/sessionbean类型的架构的时候,你可以把已加载的持久对象在sessionbean层和servlet/JSP层之间来回传递。使用新的session来为每个请求服务,使用Session.merge()或者Session.saveOrUpdate()来与数据库同步。在两层结构中,考虑使用长持久上下文(longpers

netfjfzlj 2016-03-14   4196   0
P13

  hibernate4实战 之 第二部分 文档

Hibernate4实战之第二部分:Hibernate的基本配置2013-05-1101:32:00标签:HYPERLINK"http://blog.51cto.com/tag-Hibernate.html"\t"_blank"HibernateHYPERLINK"http://blog.51cto.com/tag-%E7%BC%96%E7%A8%8B.html"\t"_blank"编程HYPERLINK"http://blog.51cto.com/tag-c3p0.html"\t"_blank"c3p0HYPERLINK"http://blog.51cto.com/tag-Java.html"\t"_blank"JavaHYPERLINK"http://blog.51cto.com/tag-%E6%95%B0%E6%8D%AE%E5%BA%93.html"\t"_blank"数据库HYPERLINK"http://blog.51cto.com/zt/617"\t"_blank"INCLUDEPICTURE"http://3001448.blog.51cto.com/image/zt/big.png"\*MERGEFORMATINET原创作品,允许转载,转载时请务必以超链接形式标明文章HYPERLINK"http://3001448.blog.51cto.com/2991448/1205817"\t"_blank"原始出处、作者信息和本声明。否则将追究法律责任。HYPERLINK"http://3001448.blog.51cto.com/2991448/1205817"http://3001448.blog.51cto.com/2991448/1205817可编程的配置方式-1如果在配置cfg.xml的时候,不想在里面配置hbm.xml怎么办呢?可在程序里使用可编程的配置方式,也就是使用程序来指定在cfg.xml里面的配置信息,不推荐这种方式。如下:Configurationcfg=newConfiguration()   .addResource("Item.hbm.xml")   .addResource("Bid.hbm.xml"); 一个替代方法(有时是更好选择)是,指定被映射的类,让Hibernate帮你寻找映射定义文件:Configurationcfg=newConfiguration()   .addClass(org.hibernate.auction.Item.class)   .addClass(org.hibernate.auction.Bid.class);这种方式消除了任何对文件名的硬编码可编程的配置方式-2还可以通过编程的方式来指定配置属性:Configurationcfg=newConfiguration()   .addClass(org.hibernate.auction.Item.class)   .setProperty("hibernate.dialect","org.hibernate.dialect.MySQLInnoDBDialect")   .setProperty("hibernate.connection.datasource","java:comp/env/jdbc/test")   .setProperty("hibernate.order_updates","true");其他可以传入配置属性的方式:1:properties文件2:xml文件3:设置Java的系统属性,形如:java–Dproperty=value另外要注意一点:org.hibernate.cfg.Configuration实例被设计成启动期间(startup-time)对象,一旦SessionFactory创建完成它就被丢弃了。 与数据库连接的配置有两种方法,一种是JDBC,一种是DataSourceJDBC的配置INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/21/c7b4a79cc0e14038212cc6d54ba26252__%E5%9B%BE%E7%89%871.png"\*MERGEFORMATINET示例:<propertyame="connection.driver_class">oracle.jdbc.driver.OracleDriver</property><propertyname="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property><propertyname="connect

netfjfzlj 2016-03-14   778   0
P10

  hibernate4实战 之 第一部分 hibernate入门 文档

Hibernate4实战之第一部分Hibernate入门2013-05-1101:31:00标签:HYPERLINK"http://blog.51cto.com/tag-Hibernate.html"\t"_blank"HibernateHYPERLINK"http://blog.51cto.com/tag-Hibernate4.html"\t"_blank"Hibernate4HYPERLINK"http://blog.51cto.com/zt/617"\t"_blank"INCLUDEPICTURE"http://3001448.blog.51cto.com/image/zt/big.png"\*MERGEFORMATINET原创作品,允许转载,转载时请务必以超链接形式标明文章HYPERLINK"http://3001448.blog.51cto.com/2991448/1205818"\t"_blank"原始出处、作者信息和本声明。否则将追究法律责任。HYPERLINK"http://3001448.blog.51cto.com/2991448/1205818"http://3001448.blog.51cto.com/2991448/1205818Hibernate是什么   Hibernate是一个轻量级的ORMapping框架  ORMapping原理(ObjectRelationalMapping) INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/21/bce2ea80efb685abf97a312ebcf61b34__1.JPG"\*MERGEFORMATINETORMapping基本对应规则:1:类跟表相对应2:类的属性跟表的字段相对应3:类的实例与表中具体的一条记录相对应4:一个类可以对应多个表,一个表也可以对应对个类5:DB中的表可以没有主键,但是Object中必须设置主键字段6:DB中表与表之间的关系(如:外键)映射成为Object之间的关系 7:Object中属性的个数和名称可以和表中定义的字段个数和名称不一样 ORMapping的基本实现方式:使用JDBC,用SQL来操作数据库,只是看动态生成还是人工写代码来实现。大家想想,我们实现过ORMapping吗? INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/21/fef823b1bb37a91ec3013fe2bb441ffb__2.JPG"\*MERGEFORMATINET INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/21/8792eaf947c4702ef7556c32cbbe2fe9__3.JPG"\*MERGEFORMATINETHibernate能干什么:   Hibernate主要用来实现Java对象和表之间的映射,除此之外还提供还提供数据查询和获取数据的方法,可以大幅度减少开发时人工使用SQL和JDBC处理数据的时间。Hibernate的目标是对于开发者通常的数据持久化相关的编程任务,解放其中的95%。对于以数据为中心的程序来说,它们往往只在数据库中使用存储过程来实现商业逻辑,Hibernate可能不是最好的解决方案;对于那些在基于Java的中间层应用中,它们实现面向对象的业务模型和商业逻辑的应用,Hibernate是最有用的。  Hibernate可以帮助你消除或者包装那些针对特定厂商的SQL代码,并且帮你把结果集从表格式的表示形式转换到一系列的对象去。INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/21/839e032a79e7826912b1c67e51c18f69__4.JPG"\*MERGEFORMATINET一个非常简要的Hibernate体系结构的高层概要图INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/21/6f6ef5745fb905fd91537ca799ca2b1a__5.JPG"\*MERGEFORMATINETHibernate运行时体系结构“最小”的体系结构方案,要求应用程序提供自己的JDBC连接并管理自己的事务。这种方案使用了HibernateAPI的最小子集. INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/21/c305b617ab7081c270a20836ba1dd

netfjfzlj 2016-03-14   567   0
P15

  hibernate4实战 之 第三部分:hibernate的基本开发 文档

Hibernate4实战之第三部分:Hibernate的基本开发2013-05-1101:33:00标签:HYPERLINK"http://blog.51cto.com/tag-Hibernate.html"\t"_blank"HibernateHYPERLINK"http://blog.51cto.com/tag-SQL.html"\t"_blank"SQLHYPERLINK"http://blog.51cto.com/tag-%E8%A1%8C%E4%B8%9A%E6%95%B0%E6%8D%AE.html"\t"_blank"行业数据HYPERLINK"http://blog.51cto.com/tag-%E6%95%B0%E6%8D%AE%E5%BA%93.html"\t"_blank"数据库HYPERLINK"http://blog.51cto.com/tag-%E5%AF%B9%E8%B1%A1.html"\t"_blank"对象HYPERLINK"http://blog.51cto.com/zt/617"\t"_blank"INCLUDEPICTURE"http://3001448.blog.51cto.com/image/zt/big.png"\*MERGEFORMATINET原创作品,允许转载,转载时请务必以超链接形式标明文章HYPERLINK"http://3001448.blog.51cto.com/2991448/1205816"\t"_blank"原始出处、作者信息和本声明。否则将追究法律责任。HYPERLINK"http://3001448.blog.51cto.com/2991448/1205816"http://3001448.blog.51cto.com/2991448/12058161:瞬时(Transient)-由new操作符创建,且尚未与HibernateSession关联的对象被认定为瞬时的。瞬时对象不会被持久化到数据库中,也不会被赋予持久化标识(identifier)。如果瞬时对象在程序中没有被引用,它会被垃圾回收器销毁。使用HibernateSession可以将其变为持久状态,Hibernate会自动执行必要的SQL语句。 2:持久(Persistent)-持久的实例在数据库中有对应的记录,并拥有一个持久化标识。持久的实例可能是刚被保存的,或刚被加载的,无论哪一种,按定义,它存在于相关联的Session作用范围内。Hibernate会检测到处于持久状态的对象的任何改动,在当前操作单元执行完毕时将对象数据与数据库同步。开发者不需要手动执行UPDATE。将对象从持久状态变成瞬时状态同样也不需要手动执行DELETE语句。 3:脱管(Detached)-与持久对象关联的Session被关闭后,对象就变为脱管的。对脱管对象的引用依然有效,对象可继续被修改。脱管对象如果重新关联到某个新的Session上,会再次转变为持久的,在脱管期间的改动将被持久化到数据库。INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/21/41af9144df34dda7df09323551ff1c4b__%E6%9C%AA%E5%91%BD%E5%90%8D.PNG"\*MERGEFORMATINET 通过Session接口来操作Hibernate新增——save方法、persist方法1:persist()使一个临时实例持久化。然而,它不保证立即把标识符值分配给持久性实例,这会发生在flush的时候。persist()也保证它在事务边界外调用时不会执行INSERT语句。这对于长期运行的带有扩展会话/持久化上下文的会话是很有用的。2:save()保证返回一个标识符。如果需要运行INSERT来获取标识符(如"identity"而非"sequence"生成器),这个INSERT将立即执行,不管你是否在事务内部还是外部。这对于长期运行的带有扩展会话/持久化上下文的会话来说会出现问题。 删除——delete方法修改——有四种方法来做,分别是:1:直接在Session打开的时候load对象,然后修改这个持久对象,在事务提交的时候,会自动flush到数据库中。2:修改托管对象,可用update或merge方法3:自动状态检测:saveOrUpdate方法update和merge方法1:如果数据库里面存在你要修改的记录,update每次是直接执行修改语句;而merge是先在缓存中查找,缓存中没有相应数据,就到数据库去查询,然后再合并数据,如果数据是一样的,那么merge方法不会去做修改,如果数据有不一样的地方,

netfjfzlj 2016-03-14   498   0
P12

  hibernate4实战 之 第四部分:关系映射 文档

Hibernate4实战之第四部分:关系映射2013-05-1101:33:00标签:HYPERLINK"http://blog.51cto.com/tag-Hibernate.html"\t"_blank"HibernateHYPERLINK"http://blog.51cto.com/tag-Java.html"\t"_blank"JavaHYPERLINK"http://blog.51cto.com/tag-%E7%B1%BB.html"\t"_blank"类HYPERLINK"http://blog.51cto.com/tag-SQL.html"\t"_blank"SQLHYPERLINK"http://blog.51cto.com/tag-String.html"\t"_blank"StringHYPERLINK"http://blog.51cto.com/zt/617"\t"_blank"INCLUDEPICTURE"http://3001448.blog.51cto.com/image/zt/big.png"\*MERGEFORMATINET原创作品,允许转载,转载时请务必以超链接形式标明文章HYPERLINK"http://3001448.blog.51cto.com/2991448/1205815"\t"_blank"原始出处、作者信息和本声明。否则将追究法律责任。HYPERLINK"http://3001448.blog.51cto.com/2991448/1205815"http://3001448.blog.51cto.com/2991448/1205815数据表之间的关系分为三类:一对一、一对多、多对多一对一数据表(部门表 和 部门主管表)一对多数据表(部门表 和 部门下的人员表)多对多数据表(部门表 和 人员表) INCLUDEPICTURE"http://sishuok.com/forum/upload/2012/2/21/ba8cdefeaa03414a6b2ef409df61f73a__1.bmp"\*MERGEFORMATINET根据相互寻找的关系又分:单向和双向对象一对一(双向)java代码:HYPERLINK"http://sishuok.com/forum/blogPost/list/2479.html"查看HYPERLINK"http://sishuok.com/forum/blogPost/list/2479.html"复制到剪贴板HYPERLINK"http://sishuok.com/forum/blogPost/list/2479.html"打印public class A {  private B b = null;  }  public class B {  private A a = null;  }  n对象一对多 (双向)  public class A {  private B b = null;  }  public class B {  private Collection<A> colA = null;  }  n对象多对多 (双向)  public class A {  private Collection<B> colB = null;  }  public class B {  private Collection<A> colA = null;  }   双向一对多是最常用的映射关系<key>元素<key>元素在父映射元素定义了对新表的连接,并且在被连接表中定义了一个外键引用原表的主键的情况下经常使用。java代码:HYPERLINK"http://sishuok.com/forum/blogPost/list/2479.html"查看HYPERLINK"http://sishuok.com/forum/blogPost/list/2479.html"复制到剪贴板HYPERLINK"http://sishuok.com/forum/blogPost/list/2479.html"打印<key  column="columnname"(1)  on-delete="noaction|cascade"(2)  property-ref="propertyName"(3)  not-null="true|false"(4)  update="true|false"(5)  unique="true|false"(6)  />  (1)column(可选):外键字段的名称。也可以通过嵌套的<column>指定。(2)on-delete(可选,默认是noacti

netfjfzlj 2016-03-14   631   0

关键词

最新上传

热门文档