Hibernate 是当今主流的java持久层框架之一,它的核心就是ORM对象关系的映射。下面是我刚开始学习写的一个简单的ORM demo。
第一步:去官网http://hibernate.org/orm/releases/下载一个Hibernate的包,选择自己的需要的版本。
我是直接用的老师给下载好的5.2.10版本。
第二步:在myEclipse里创建一个java工程。
第三步:将下载的hibernate的包required文件中的jar包都拷贝到项目工程的lib文件夹下
选中项目右键-->Build Path-->Add External Jars-->选择存放hibernate jar 包的路径-->选择jar包
第四步:在MySQL中创建一个名称为hibernate的数据库,在这个数据库上创建一个名为user的数据表。我安装的MySQL版本是 5.7。
第五步:编写实体类(持久化类) O
package org.test.entity; private int id; private String uname; private int age; private String sex; private String city; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String toString(){ return "User [id="+id+",uname="+uname+",age="+age+",sex="+sex+",city="+city+"]"; } } |
第六步:编写映射文件User.hbm.xml
实体类User目前还不具备持久化操作的能力,而Hibernate需要知道实体类User映射到数据库 Hibernate中的哪个表,以及类中的哪个属性对应数据库表中的哪一个字段,这些都需要在映射文件中配置。
在实体类User所在的包中,创建一个名称为User.hbm.xml的映射文件,在该文件中定义了实体类User的属性是如何映射到user表的列上的。
我们可以下载好hibernate需要的映射文件导入到工程中去,除此之外,通常myEclipse会自己附带hibernate,所以这里记录一下如何直接在myEclipse中创建hbm.xml映射文件。
1.右键点击工程new弹出New框,在框中选择XML(Basic Templates)。下一步后在.xml前加上hbm,整个文件出来之后就是“.hbm.xml”为后缀的文件,然后next
2.选择第一个单选框,点击next
3.选择第二项,然后找到我们要用的dtd,点击next,会出来一个界面,不用管它直接点击finish
4.然后User.hbm.xml映射文件就建好了
Hibernate的映射文件反映了持久化类和数据库表的映射信息,
而Hibernate的配置文件则主要用来配置数据库连接以及Hibernate运行时所需要的各个属性的值.
从下载解压的文件夹中选择project文件夹下的etc文件夹,打开文件夹找到hibernate.cfg.xml拖拽到项目的src目录下,根据需要修改相应配置信息
myEclipse连接数据库,可以用jdbc接口,也有另一种不用jdbc的方法:
1.window-->Open Perspctive-->MyEclipse Database Explorer-->OK
2.左侧空白处右键-->New-->输入相关信息
3.点击Test Driver测试是否配置成功,输入访问数据库密码。
注:
但是在测试时,出现了如下的错误,使用驱动程序执行数据库登陆时出现错误,经过检查和上网查询发现是导入自己下载的数据库jar包时,驱动文件放在了中文目录,更改了存放目录后错误解决。
因此存放驱动的文件最好是英文目录,在测试时确定mysql数据库已经打开,服务已经打开,否则测试会报错
测试成功后界面如下:
hibernate.cfg.xml
|
第八步:编写测试类,进行测试
在项目中src下新建一个org.test.demo的包,然后再包内建立一个名为UserTest.java的文件,该文件是用来测试的类文件。
package org.test.demo; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.test.entity.User; public class UserTest { //定义变量 Configuration config; SessionFactory sessionFactory; Session session; Transaction transaction; //before表示在方法执行前执行 @Before public void SetUp() { //1.加载hibernate.cfg.xml配置 config=new Configuration().configure(); //2.获取SessionFactory sessionFactory= config.buildSessionFactory(); //3.获得一个session session=sessionFactory.openSession(); //4.开始事务 transaction=session.beginTransaction(); } //添加操作 @Test public void insert() { //5.操作 User user=new User(); // user.setId(1); user.setUname("zhangsan"); user.setAge(20); user.setSex("m"); user.setCity("guangzhou"); session.save(user); } //删除操作 @Test public void delete() { //先查询 User user=(User)session.get(User.class,1); //再删除 if(user!=null) { session.delete(user); } } //查询操作 @Test public void select() { User user=(User)session.get(User.class, 1); System.out.println(user); } //更新操作 @Test public void update() { User user=new User(); //user.setId(1); user.setUname("zhangsan"); user.setAge(20); user.setSex("m"); //修改地址为beijing user.setCity("beijing"); //存在就更新,不存在就执行插入操作 session.saveOrUpdate(user); } //After表示在方法执行结束后执行 @After public void closeTransaction() { //6.提交事务 transaction.commit(); //7.关闭资源 session.close(); sessionFactory.close(); } } |
使用单元测试框架JUnit4进行单元测试,不需要main方法,就可以直接对类中的方法进行测试。@Test是用来测试的注解。
进度条 为绿色表明运行结果正确,如果为红色则表示有错误。在数据库中查询表数据,结果如图:
表明user表中数据添加成功。
测试运行select()方法后,控制台信息如图:
测试更新方法update()时,结果如图:
数据库中表数据为:
测试删除方法delete()删除id为2后,数据表为:
测试成功!
当然,在测试过程中,遇到了一些问题,也折腾了很长时间:
1.在测试更新方法update()时:
错误信息:javax.persistence.OptimisticLockException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.internal.ExceptionConverterImpl.wrapStaleStateException(ExceptionConverterImpl.java:212)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:86)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:155)
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:162)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1441)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:491)
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3201)
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2411)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:467)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:146)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38)
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:220)
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68)
at org.test.demo.UserTest.closeTransaction(UserTest.java:143)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
直观翻译过来是:批量更新从更新0返回意外的行数;实际的行数0;预期:1
这样的问题,不注意的话也挺无所适从:这个问题是主键一开始设置为自增长,而在我插入数据时又设置了ID值导致的。
我的解决方法是插入数据时,不重新设置Id值,数据库会自动给出一个自增长的id值。
2.测试删除方法delete()时,
错误信息:
java.lang.IllegalArgumentException: attempt to create delete event with null entity
at org.hibernate.event.spi.DeleteEvent.
at org.hibernate.internal.SessionImpl.delete(SessionImpl.java:927)
at org.test.demo.UserTest.delete(UserTest.java:91)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
直观翻译过来是:企图用null实体创建删除事件
报错,但是能删除
解决办法是:删除之前,先判断要删除的对象是否为空
if(user!=null)}
问题就解决了。