收藏 分销(赏)

2024年hibernate面试题.doc

上传人:快乐****生活 文档编号:8225084 上传时间:2025-02-08 格式:DOC 页数:34 大小:59.54KB
下载 相关 举报
2024年hibernate面试题.doc_第1页
第1页 / 共34页
2024年hibernate面试题.doc_第2页
第2页 / 共34页
2024年hibernate面试题.doc_第3页
第3页 / 共34页
2024年hibernate面试题.doc_第4页
第4页 / 共34页
2024年hibernate面试题.doc_第5页
第5页 / 共34页
点击查看更多>>
资源描述

1、1.Hibernate工作原理及为何要用? 原理: 1.读取并解析配备文献 2.读取并解析映射信息,创建SessionFactory 3.打开Sesssion 4.创建事务Transation 5.持久化操作 6.提交事务 7.关闭Session 8.关闭SesstionFactory 为何要用: 1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。 2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作 3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。 4. hiber

2、nate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。 2Hibernate是怎样延迟加载? 1. Hibernate2延迟加载实现:a)实体对象 b)集合(Collection) 2. Hibernate3 提供了属性的延迟加载功效 当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节约了服务器的内存开销,从而提升了服务器的性能。 3Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系) 类与类之间的关系重要体目前表与表之间的关系进行操

3、作,它们城市对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配备文献中的many-to-one、one-to-many、many-to-many、 4说下Hibernate的缓存机制 1. 内部缓存存在Hibernate中又叫一级缓存,属于应用事物级缓存 2. 二级缓存: a) 应用及缓存 b) 分布式缓存 条件:数据不会被第三方修改、数据大小在可接收范围、数据更新频率低、同一数据被系统频繁使用、非 核心数据 c) 第三方缓存的实现 5Hibernate的查询方式 Sql、Criteria,object comptosition Hql: 1、 属性查询 2、 参数查询、命名参数

4、查询 3、 关联查询 4、 分页查询 5、 统计函数 6怎样优化Hibernate? 1.使用双向一对多关联,不使用单向一对多 2.灵活使用单向一对多关联 3.不用一对一,用多对一取代 4.配备对象缓存,不使用集合缓存 5.一对多集合使用Bag,多对多集合使用Set 6. 继承类使用显式多态 7. 表字段要少,表关联不要怕多,有二级缓存撑腰 /答案二:hibernate工作原理:1、通过Configuration().configure();读取并解析hibernate.cfg.xml配备文献。2、由hibernate.cfg.xml中的读取解析映射信息。3、通过config.buildSes

5、sionFactory();/得到sessionFactory。4、sessionFactory.openSession();/得到session。5、session.beginTransaction();/开启事务。6、persistent operate;6、session.getTransaction().commit();/提交事务7、关闭session;8、关闭sessionFactory;hibernate优点:1、封装了jdbc,简化了诸多重复性代码。2、简化了DAO层编码工作,使开发更对象化了。3、移植性好,支持各种数据库,假如换个数据库只要在配备文献中变换配备就能够了,不用变

6、化hibernate代码。4、支持透明持久化,因为hibernate操作的是纯粹的(pojo)java类,没有实现任何接口,没有侵入性。因此说它是一个轻量级框架。hibernate延迟加载:get不支持延迟加载,load支持延迟加载。1、hibernate2对 实体对象和集合 实现了延迟加载2、hibernate3对 提供了属性的延迟加载功效hibernate延迟加载就是当使用session.load(User.class, 1)或者session.createQuery()查询对象或者属性的时候这个对象或者属性并没有在内存中,只有当程序操作数据的时候,才会存在内存中,这么就实现延迟加载,节约

7、了内存的开销,从而提升了服务器的性能。Hibernate的缓存机制一级缓存:session级的缓存也叫事务级的缓存,只缓存实体,生命周期和session一致。不能对其进行管理。不用显示的调用。二级缓存:sessionFactory缓存,也叫进程级的缓存,使用第3方插件实现的,也值缓存实体,生命周期和sessionFactory一致,能够进行管理。首先配备第3放插件,我们用的是EHCache,在hibernate.cfg.xml文献中加入true在映射中也要显示的调用,二级缓存之查询缓存:对一般属性进行缓存。假如关联的表发生了修改,那么查询缓存的生命周期也结束了。在程序中必须手动启用查询缓存:q

8、uery.setCacheable(true);优化Hibernate1、使用一对多的双向关联,尽也许从多的一端维护。2、不要使用一对一,尽也许使用多对一。3、配备对象缓存,不要使用集合缓存。4、表字段要少,表关联不要怕多,有二级缓存撑腰。(1)一般情况下,关系数据模型与对象模型之间有哪些匹配关系(多项选择)A)表对应类B)统计对应对象C)表的字段对应类的属性(2)如下有关SessionFactory的说法哪些正确?(多项选择))一个SessionFactory对象对应一个数据库存储源。C)SessionFactory是重量级的对象,不应当随意创建。假如系统中只有一个数据库存储源,只需要创建一

9、个(3)Customer类中有一个Set类型的orders属性,用来存储Order订单对象,在Customer.hbm.xml文献中,用哪个元素映射orders属性?A) B) C) D)(4)元素有一个cascade属性,假如希望Hibernate级联保存集合中的对象,casecade属性应当取什么值?(单项选择))save-update(5)如下哪些属于Session的措施?A)load()B)save()C)delete()D)update()E)open()F)close()(6)如下程序的打印成果是什么?(单项选择)1. tx=session.beginTransaction();

10、2. Customerc1=(Customer)session.load(Customer.class,newLong(1); 3. Customerc2=(Customer)session.load(Customer.class,newLong(1); 4. System.out.println(c1=c2); 5. mit(); 6. session.close();打印true(7)如下程序代码对Customer的name属性修改了两次:1. tx=session.beginTransaction(); 2. Customercustomer=(Customer)session.load

11、(Customer.class, 3. newLong(1); 4. customer.setName(Jack); 5. customer.setName(Mike); 6. mit();执行以上程序,Hibernate需要向数据库提交几条update语句?(单项选择)B,1 (8)在持久化层,对象分为哪些状态?(多项选择)A)暂时状态C)游离状态D)持久化状态(9)对于如下程序,Customer对象在第几行变为持久化状态?(单项选择)1. Customercustomer=newCustomer();/line1 2. customer.setName(Tom);/line2 3. Ses

12、sionsession1=sessionFactory.openSession();/line3 4. Transactiontx1=session1.beginTransaction();/line4 5. session1.save(customer);/line4 6. mit();/line5 7. session1.close();/line6A) line1 B)line2 C)line3 D)line4 E)line5 F)line6(10)对于如下程序,Customer对象在第几行变为游离状态?(单项选择)1. Customercustomer=newCustomer();/l

13、ine1 2. customer.setName(Tom);/line2 3. Sessionsession1=sessionFactory.openSession();/line3 4. Transactiontx1=session1.beginTransaction();/line4 5. session1.save(customer);/line4 6. mit();/line5 7. session1.close();/line6)line6(11)如下哪一个检索方略利用了外连结查询?(单项选择)A)立即检索 B)延迟检索 C)迫切左外连结检索(12)假设对Customer类的orde

14、rs集合采取延迟检索方略,编译或运行如下程序,会出现什么情况(单项选择)1. Sessionsession=sessionFactory.openSession(); 2. tx=session.beginTransaction(); 3. Customercustomer=(Customer)session.get(Customer.class,newLong(1); 4. mit(); 5. session.close(); 6. IteratororderIterator=customer.getOrders().iterator();A)编译犯错 B)编译通过,并正常运行 C)编译通过

15、,但运行时抛出异常(13)有关HQL与SQL,如下哪些说法正确?(多项选择)A)HQL与SQL没什么差异B)HQL面对对象,而SQL操纵关系数据库C)在HQL与SQL中,都包括select,insert,update,delete语句D)HQL仅用于查询数据,不支持insert,update和delete语句(14)事务隔离级别是由谁实现的?(单项选择)A)Java应用程序 B)Hibernate C)数据库系统 D)JDBC驱动程序(15)悲观锁与乐观锁,哪个具备很好的并发性能?(单项选择)A)悲观锁 B)乐观锁答案:(1)A,B,C (2)B,C (3)A (4)D (5)A,B,C,D,

16、F (6)C (7)B (8)A,C,D (9)D (10)F (11)C (12)C (13)B,D (14)C (15)BHibernate对象的三种状态是什么? 瞬时态(Transient)、 持久态(Persistent)、脱管态(Detached)。处在持久态的对象也称为PO(Persistence Object),瞬时对象和脱管对象也称为VO(Value Object)。瞬时态由new命令开辟内存空间的java对象,eg. Person person = new Person(”amigo”, “女”);假如没有变量对该对象进行引用,它将被java虚拟机回收。瞬时对象在内存孤立存在

17、,它是携带信息的载体,不和数据库的数据有任何关联关系,在Hibernate中,可通过session的save()或 saveOrUpdate()措施将瞬时对象与数据库有关联,并将数据对应的插入数据库中,此时该瞬时对象转变成持久化对象。持久态处在该状态的对象在数据库中具备对应的统计,并拥有一个持久化标识。假如是用hibernate的delete()措施,对应的持久对象就变成瞬时对象,因数据库中的对应数据已被删除,该对象不再与数据库的统计关联。当一个session执行close()或clear()、evict()之后,持久对象变成脱管对象,此时持久对象会变成脱管对象,此时该对象虽然具备数据库识别值

18、,但它已不在HIbernate持久层的管理之下。持久对象具备如下特点:1. 和session实例关联;2. 在数据库中有与之关联的统计。脱管态当与某持久对象关联的session被关闭后,该持久对象转变为脱管对象。当脱管对象被重新关联到session上时,并再次转变成持久对象。脱管对象拥有数据库的识别值,可通过update()、saveOrUpdate()等措施,转变成持久对象。脱管对象具备如下特点:1. 本质上与瞬时对象相同,在没有任何变量引用它时,JVM会在适当的时候将它回收;2. 比瞬时对象多了一个数据库统计标识值。Detached Object(游离对象)有什么好处? Detached

19、Object(游离对象)能够传递到任何层直到体现层而不是用任何DTO(Data Transfer Objects). 然后你还能够重新把游离对象赋给另外一个Session. jdbc、hibernate、ibatis的区分? jdbc:手动手动写sqldelete、insert、update要将对象的值一个一个取出传到sql中,不能直接传入一个对象。select:返回的是一个resultset,要从ResultSet中一行一行、一个字段一个字段的取出,然后封装到一个对象中,不直接返回一个对象。ibatis的特点:半自动化sql要手动写delete、insert、update:直接传入一个对象s

20、elect:直接返回一个对象hibernate:全自动不写sql,自动封装delete、insert、update:直接传入一个对象select:直接返回一个对象 Hibernate怎样实现数据表映射的继承关系? 1、两个表,子类重复父类的属性。2、一个表,子类父类共用一个表 3、两个表,子类引用父类的主键,享用公共的字段或属性。 批量删除Query query=session.createQuery(”update”或”delete”);query.executeUpdate();Hibernate中Query对象的使用 1 个或多个属性查询:Query query=session.crea

21、teQuery(”select customername,customerid from Customer”)List l=query.list();For(int i=0;il.size();i+)Obejct object=(Object)l.get(i);Object0 object1分组: “select count(*),productname from Product group by productname order by productname”取值与属性同样配备的查询,在*.hbm.xml中 Query query=session.getNamedQuery(sql);联接

22、1”from Customer as customer join fetch customer.buySet”:将多的放到buySet属性中,得出的结是Customer有一个,Buy有多个联接2“from Customer as customer join customer.buySet”:得出的对象,customer与buy是1对1子查询:”from Customer as customer where (select count(*) from customer.buySet)1Hibernate中Criteria 和DetachedCriteria的作用是什么? Criteria c=s

23、ession.createCriteria(Customer.class);/设置条件c.add(Expression.ge(“字段名”,”值对象”)ge:=gt:le:=lt:eq:=/排序c.addOrder(Order.asc(“字段名”)/分页c.setFirstResult(1)/从第2行开始提取c.setMaxResults(5)/返回5行DetachedCriteria产生时不需要sessionDetachedCriteria dc= DetachedCriteria.forClass(Customer.class)Criteria c=Dc.getExecutableCrite

24、ria(session)Hibernate中数据表映射关系重要有什么类型? one-to-manyinverse:主控方,外键的关系有谁控制inverse=false 是主控方,外键是由它控制的inverse=true 是被控方,外键与它没关系要想实现主控方的控制必须将被控方作为主控方的属性cascade:级联主表增从表增主表修从表修主表删从表删lazy:延迟lazy=false:一下将所有的内容取出,不延时(常用)lazy=true:取出部分内容,其他内容动态去取通过get能够取出对方的所有内容hibernate的核心类是什么,它们的相互关系是什么?重要的措施是什么? Configurati

25、onSessionFactorySession如下措施SaveloadUpdateDelete Query q=CreateQuery(“from Customer where customerName=:customerName”)beginTransactioncloseTransactionCommit()在myeclipse加入hibernate环境的全过程是什么? 1.Db-browers加入配备连接2.新建工程3.加入hibernate环境,指定*.hbm.xml及HibernateSessionFactory文献所在的位置 详细内容参见此前写的hibernate的第一个小例子 面

26、试中常出现的两个Hibernate面试题及解答 1.在数据库中条件查询速度很慢的时候,怎样优化?1.建索引2.减少表之间的关联3.优化sql,尽也许让sql很快定位数据,不要让sql做全表查询,应当走索引,把数据量大的表排在前面4.简化查询字段,没用的字段不要,已经对返回成果的控制,尽也许返回少许数据2.在hibernate中进行多表查询,每个表中各取几个字段,也就是说查询出来的成果集并没有一个实体类与之对应,怎样处理这个问题?处理方案一,按照Object数据取出数据,然后自己组bean处理方案二,对每个表的bean写结构函数,例如表一要查出field1,field2两个字段,那么有一个结构函

27、数就是Bean(type1 filed1,type2 field2) ,然后在hql里面就能够直接生成这个bean了。详细怎么用请看有关文档,我说的不是很清楚。session.load()和session.get()的区分Session.load/get措施均能够依照指定的实体类和id从数据库读取统计,并返回与之对应的实体对象。其区分在于:假如未能发觉符合条件的统计,get措施返回null,而load措施会抛出一个ObjectNotFoundException。Load措施可返回实体的代理类实例,而get措施永远直接返回实体类。load措施能够充足利用内部缓存和二级缓存中的既有数据,而get措

28、施则仅仅在内部缓存中进行数据查找,如没有发觉对应数据,将越过二级缓存,直接调用SQL完成数据读取。Session在加载实体对象时,将通过的过程:首先,Hibernate中维持了两级缓存。第一级缓存由Session实例维护,其中保持了Session目前所有关联实体的数据,也称为内部缓存。而第二级缓存则存在于SessionFactory层次,由目前所有由本 SessionFactory结构的Session实例共享。出于性能考虑,防止无谓的数据库访问,Session在调用数据库查询功效之前,会先在缓存中进行查询。首先在第一级缓存中,通过实体类型和id进行查找,假如第一级缓存查找命中,且数据状态合法,

29、则直接返回。之后,Session会在目前“NonExists”统计中进行查找,假如“NonExists”统计中存在同样的查询条件,则返回null。 “NonExists”统计了目前Session实例在之前所有查询操作中,未能查询到有效数据的查询条件(相称于一个查询黑名单列表)。如此一来,假如 Session中一个无效的查询条件重复出现,即可迅速作出判断,从而取得最佳的性能体现。对于load措施而言,假如内部缓存中未发觉有效数据,则查询第二级缓存,假如第二级缓存命中,则返回。如在缓存中未发觉有效数据,则发起数据库查询操作(Select SQL),如通过查询未发觉对应统计,则将本次查询的信息在“N

30、onExists”中加以统计,并返回null。依照映射配备和Select SQL得到的ResultSet,创建对应的数据对象。将其数据对象纳入目前Session实体管理容器(一级缓存)。执行Interceptor.onLoad措施(假如有对应的Interceptor)。将数据对象纳入二级缓存。假如数据对象实现了LifeCycle接口,则调用数据对象的onLoad措施。返回数据对象。Hibernate的主键生成机制1) assigned主键由外部程序负责生成,无需Hibernate参加。2) hilo通过hi/lo 算法实现的主键生成机制,需要额外的数据库表保存主键生成历史状态。3) seqhi

31、lo与hilo 类似,通过hi/lo 算法实现的主键生成机制,只是主键历史状态保存在Sequence中,适合用于支持Sequence的数据库,如Oracle。4) increment主键按数值次序递增。此方式的实现机制为在目前应用实例中维持一个变量,以保存着目前的最大值,之后每次需要生成主键的时候将此值加1作为主键。这种方式也许产生的问题是:假如目前有多个实例访问同一个数据库,那么因为各个实例各自维护主键状态,不一样实例也许生成同样的主键,从而导致主键重复异常。因此,假犹如一数据库有多个实例访问,此方式必须防止使用。5) identity采取数据库提供的主键生成机制。如DB2、SQL Serv

32、er、MySQL中的主键生成机制。6) sequence采取数据库提供的sequence 机制生成主键。如Oralce 中的Sequence。7) native由Hibernate依照底层数据库自行判断采取identity、hilo、sequence其中一个作为主键生成方式。8) uuid.hex由Hibernate基于128 位唯一值产生算法生成16 进制数值(编码后以长度32 的字符串表示)作为主键。9) uuid.string与uuid.hex 类似,只是生成的主键未进行编码(长度16)。在某些数据库中也许出现问题(如PostgreSQL)。10) foreign使用外部表的字段作为主键

33、。一般而言,利用uuid.hex方式生成主键将提供最佳的性能和数据库平台适应性。这10中生成OID标识符的措施,increment 比较常用,把标识符生成的权力交给Hibernate处理.不过当同时多个Hibernate应用操作同一个数据库,甚至同一张表的时候.就推荐使用identity 依赖底层数据库实现,不过数据库必须支持自动增加,当然针对不一样的数据库选择不一样的措施.假如你不能确定你使用的数据库详细支持什么的情况下.能够选择用native 让Hibernate来帮选择identity,sequence,或hilo.另外因为常用的数据库,如Oracle、DB2、SQLServer、MyS

34、ql 等,都提供了易用的主键生成机制(Auto-Increase 字段或者Sequence)。我们能够在数据库提供的主键生成机制上,采取generator-class=native的主键生成方式。不过值得注意的是,某些数据库提供的主键生成机制在效率上未必最佳,大量并发insert数据时也许会引起表之间的互锁。数据库提供的主键生成机制,往往是通过在一个内部表中保存目前主键状态(如对于自增型主键而言,此内部表中就维护着目前的最大值和递增量),之后每次插入数据会读取这个最大值,然后加上递增量作为新统计的主键,之后再把这个新的最大值更新回内部表中,这么,一次Insert操作也许导致数据库内部数次表读写

35、操作,同时伴随的尚有数据的加锁解锁操作,这对性能产生了较大影响。因此,对于并发Insert要求较高的系统,推荐采取uuid.hex 作为主键生成机制Struts,Spring,Hibernate面试题总结 收藏 Hibernate工作原理及为何要用?原理:1. 读取并解析配备文献2. 读取并解析映射信息,创建SessionFactory3. 打开Sesssion4. 创建事务Transation5. 持久化操作6. 提交事务7. 关闭Session8. 关闭SesstionFactory 为何要用: 1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。2. Hibe

36、rnate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。4. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。 2 Hibernate是怎样延迟加载?1. Hibernate2延迟加载实现:a)实体对象 b)集合(Collection)2. Hibernate3 提供了属性的延迟加载功效当Hibernate在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存

37、中,就实现了延迟加载,他节约了服务器的内存开销,从而提升了服务器的性能。3 Hibernate中怎样实现类之间的关系?(如:一对多、多对多的关系)类与类之间的关系重要体目前表与表之间的关系进行操作,它们城市对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配备文献中的many-to-one、one-to-many、many-to-many、4 说下Hibernate的缓存机制1. 内部缓存存在Hibernate中又叫一级缓存,属于应用事物级缓存2. 二级缓存:a) 应用及缓存b) 分布式缓存条件:数据不会被第三方修改、数据大小在可接收范围、数据更新频率低、同一数据被系统频繁使用、非

38、 核心数据c) 第三方缓存的实现5 Hibernate的查询方式Sql、Criteria,object comptositionHql:1、 属性查询2、 参数查询、命名参数查询3、 关联查询4、 分页查询5、 统计函数 6 怎样优化Hibernate?1. 使用双向一对多关联,不使用单向一对多2. 灵活使用单向一对多关联3. 不用一对一,用多对一取代4. 配备对象缓存,不使用集合缓存5. 一对多集合使用Bag,多对多集合使用Set6. 继承类使用显式多态7. 表字段要少,表关联不要怕多,有二级缓存撑腰 7 Struts工作机制?为何要使用Struts?工作机制:Struts的工作流程: 在w

39、eb应用开启时就会加载初始化ActionServlet,ActionServlet从 struts-config.xml文献中读取配备信息,把它们存储到各种配备对象 当ActionServlet接收到一个客户祈求时,将执行如下流程. -(1)检索和用户祈求匹配的ActionMapping实例,假如不存在,就返回祈求途径无效信息; -(2)假如ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm 对象中; -(3)依照配备信息决定是否需要表单验证.假如需要验证,就调用ActionForm的validate()措施; -(4)假如Act

40、ionForm的validate()措施返回null或返回一个不包括ActionMessage的ActuibErrors对象, 就表示表单验证成功; -(5)ActionServlet依照ActionMapping所包括的映射信息决定将祈求转发给哪个Action,假如对应的 Action实例不存在,就先创建这个实例,然后调用Action的execute()措施; -(6)Action的execute()措施返回一个ActionForward对象,ActionServlet在把客户祈求转发给 ActionForward对象指向的JSP组件; -(7)ActionForward对象指向JSP组件生

41、成动态网页,返回给客户;为何要用:JSP、Servlet、JavaBean技术的出现给我们构建强大的企业应用系统提供了也许。但用这些技术构建的系统非常的繁乱,因此在此之上,我们需要一个规则、一个把这些技术组织起来的规则,这就是框架,Struts便应运而生。基于Struts开发的应用由3类组件组成:控制器组件、模型组件、视图组件8 Struts的validate框架是怎样验证的?在struts配备文献中配备详细的错误提示,再在FormBean中的validate()措施详细调用。9 说下Struts的设计模式MVC模式: web应用程序开启时就会加载并初始化ActionServler。用户提交表单时,一个配备好的Action

展开阅读全文
部分上传会员的收益排行 01、路***(¥15400+),02、曲****(¥15300+),
03、wei****016(¥13200+),04、大***流(¥12600+),
05、Fis****915(¥4200+),06、h****i(¥4100+),
07、Q**(¥3400+),08、自******点(¥2400+),
09、h*****x(¥1400+),10、c****e(¥1100+),
11、be*****ha(¥800+),12、13********8(¥800+)。
相似文档                                   自信AI助手自信AI助手
搜索标签

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        获赠5币

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4008-655-100  投诉/维权电话:4009-655-100

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :gzh.png    weibo.png    LOFTER.png 

客服