ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
在我们的教务管理系统中,除了需要有TeacherDao,我们在后面还需要KlassDao, StudentDao等等其实的数据访问层。而这些数据访问层在进行CURD操作时,代码大部分都是相同的。在本节中,让我们共同学习如何使用抽像类与接口来改写DAO层的CURD操作。 # 基类 我们新建TestDao,并在该类中,写入`get(Long id)`及`delete(Teacher teacher)`方法,然后我们用TeacherDao来进行继承. ![https://box.kancloud.cn/36eb70c7a526600a85c85d4bf6eb396a_1234x568.png](https://box.kancloud.cn/36eb70c7a526600a85c85d4bf6eb396a_1234x568.png) 但现在问题来了,我们在调用TeacherDao的get()方法时,返回Teacher是没有问题的。但如果调用StudentDao的get()方法,则应该返回的是Student实体,而非Teacher。所以TestDao中的get(Long id)方法的返回值其实是不确定的。即:它即有可能返回的的Teacher实体,也可以返回Student实体。而java又是强类型语言,是必须指定函数的返回值的。怎么办呢? 为了解决这个问题,我们引入接口。 # 接口 新建实体接口,其它实体来继承该接口: ![https://box.kancloud.cn/38935d774d89fa371d40d9d21029ef80_962x600.png](https://box.kancloud.cn/38935d774d89fa371d40d9d21029ef80_962x600.png) 此时,我们的返回值的类型,就可以声明为该接口类型了: ![https://box.kancloud.cn/8aa51d6c6f58b34d63b88d821e881f55_1222x562.png](https://box.kancloud.cn/8aa51d6c6f58b34d63b88d821e881f55_1222x562.png) 同时,我们增加了`getFeaturedClass()`,它的返回值是一个实体类。我们共同来查看如下时序图,来看看`getFeaturedClass()`的在StudentDao进行`get`操作时的具体作用. ![https://box.kancloud.cn/512feaf0b512909e92344f2852cef0ac_1396x668.png](https://box.kancloud.cn/512feaf0b512909e92344f2852cef0ac_1396x668.png) 我们看到,在TestDao在执行`get`操作时,又调用了StudentDao中的`getFeaturedClass()`方法。而该方法决定了第6步操作同样将返回一个`Student`实体。 通过上图我们看出,要使TestDao的get()操作成功,那么继承它的实现类则必须存在`getFeaturedClass()`,否则,将导致找不到`getFeaturedClass`方法的异常。为了避免其它实现类在进行继承后可能忘记写`getFeaturedClass()`的问题,我们为其增加接口来进行约束。 ![https://box.kancloud.cn/c6e81667f52ae7dd6f613c85a50f6d56_1288x854.png](https://box.kancloud.cn/c6e81667f52ae7dd6f613c85a50f6d56_1288x854.png) # 规范接口 实际上,抽像类更多的,是在实现接口中一些具体通用性的方法。而在实现类中,去实现接口中的非通用方法。比如,在上图中,TestDao做为抽像类,其实现了具体的数据获取与删除的方法。而StudentDao做为实现类,实现了接口中非通用的`getFeaturedClass()`方法。接口做的更多的,是规范与约束程序,按照这种思想,我们再次进行改写: ![https://box.kancloud.cn/aaa639a9093a38c845ed3f057fdbda27_1334x888.png](https://box.kancloud.cn/aaa639a9093a38c845ed3f057fdbda27_1334x888.png) 至此,我们将接口做为返回类型,解决了返回值并不确认为哪种对象的问题;我们还应用接口对类进行了规范与约束;我们还应用了抽像类,来实现了那些通用的方法。如果本节中讲过的,你非常清晰的明了其中的脉络,那么恭喜你。在学习JAVA的路上,你迈出了进阶的一步。 <hr /> 具体代码: 我们对Dao接口进行补充,同时将TestDao改个名字:AbstractDao,并声明为Abstract。最后,增加TeacherDao中的接口方法. ``` /* * 在接口中声明方法 */ package com.mengyunzhi.javaee.dao; import com.mengyunzhi.javaee.entity.IdEntity; import java.io.Serializable; import java.util.Collection; /** * Dao. Interface. */ public interface Dao { Class<?> getFeaturedClass(); IdEntity get(Serializable id); Serializable create(IdEntity object); IdEntity update(IdEntity object); int delete(Serializable id); int delete(IdEntity object); Collection<?> paginate(int page, int pageSize); Collection<?> all(); } ``` 抽像类继承了接口,并实现接口声明的方法 ``` /* * $Id$ * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.mengyunzhi.javaee.dao; import com.mengyunzhi.javaee.exception.CreateException; import com.mengyunzhi.javaee.exception.UpdateException; import com.mengyunzhi.javaee.entity.IdEntity; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.TransactionException; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistryBuilder; /** * AbstractDao. */ public abstract class AbstractDao implements Serializable, Dao { /** * */ private static final long serialVersionUID = 1L; private static SessionFactory sessionFactory; protected static Session getCurrentSession() { // 每个数据库只需要一个sessionFactory,在这里进行单一实例处理。 if (null == sessionFactory) { // 实例化并加载数据库配置文件 Configuration configuration = new Configuration().configure(); // 构造服务注册对象 ServiceRegistry serviceRegistry = new ServiceRegistryBuilder() .applySettings(configuration.getProperties()) .buildServiceRegistry(); // 创建会话工厂(session factory)) sessionFactory = configuration.buildSessionFactory(serviceRegistry); } // 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话) return sessionFactory.getCurrentSession(); } public IdEntity get(Serializable id) { IdEntity object = null; // 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话) Session session = getCurrentSession(); // 开启事务(使用缓冲池进行数据库的连接) Transaction transaction = session.beginTransaction(); // 在这里,必须使用try catch finally语句。来确定会话正常关闭. // 否则,当操作数据库产生错误时,你可能需要重启mysql服务 try { // 使用Teacher.class来获取到Teacher的类名(包括包名) object = (IdEntity) session.get(getFeaturedClass(), id); // 提交事务 transaction.commit(); // 捕获异常 } catch (HibernateException e) { // 如果事务执行异常,则回滚事务 if (null != transaction) { transaction.rollback(); } // 打印异常 e.printStackTrace(); } finally { // 如果session处于开启状态,则关闭session if (session.isOpen()) { // 关闭会话 session.close(); } } return object; } public Serializable create(IdEntity object) { // 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话) Session session = getCurrentSession(); // 开启事务(使用缓冲池进行数据库的连接) Transaction transaction = session.beginTransaction(); // 在这里,必须使用try catch finally语句。来确定会话正常关闭. // 否则,当操作数据库产生错误时,你可能需要重启mysql服务 try { // 新增数据 session.save(object); // 提交事务 transaction.commit(); // 捕获异常 } catch (HibernateException e) { // 如果事务执行异常,则回滚事务 if (null != transaction) { try { transaction.rollback(); } catch (TransactionException te) { // 抛出异常 te.printStackTrace(); } } // 抛出异常 e.printStackTrace(); } finally { // 如果session处于开启状态,则关闭session if (session.isOpen()) { // 关闭会话 session.close(); } } return object.getId(); } public IdEntity update(IdEntity object) { // 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话) Session session = getCurrentSession(); // 开启事务(使用缓冲池进行数据库的连接) Transaction transaction = session.beginTransaction(); // 在这里,必须使用try catch finally语句。来确定会话正常关闭. // 否则,当操作数据库产生错误时,你可能需要重启mysql服务 try { // 删除 session.update(object); // 提交事务 transaction.commit(); // 捕获异常 } catch (HibernateException e) { // 如果事务执行异常,则回滚事务 if (null != transaction) { try { transaction.rollback(); } catch (TransactionException te) { // 抛出异常 throw (te); } } // 抛出异常 throw (e); } finally { // 如果session处于开启状态,则关闭session if (session.isOpen()) { // 关闭会话 session.close(); } } return object; } public int delete(Serializable id) { IdEntity idEntity = this.get(id); return this.delete(idEntity); } public int delete(IdEntity object) { // 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话) Session session = getCurrentSession(); // 开启事务(使用缓冲池进行数据库的连接) Transaction transaction = session.beginTransaction(); // 在这里,必须使用try catch finally语句。来确定会话正常关闭. // 否则,当操作数据库产生错误时,你可能需要重启mysql服务 try { // 删除 session.delete(object); // 提交事务 transaction.commit(); // 捕获异常 } catch (HibernateException e) { // 如果事务执行异常,则回滚事务 if (null != transaction) { try { transaction.rollback(); } catch (TransactionException te) { // 抛出异常 throw (te); } } // 抛出异常 throw (e); } finally { // 如果session处于开启状态,则关闭session if (session.isOpen()) { // 关闭会话 session.close(); } } return 0; } @SuppressWarnings("unchecked") public Collection<?> all() { // 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话) Session session = getCurrentSession(); // 开启事务(使用缓冲池进行数据库的连接) Transaction transaction = session.beginTransaction(); Collection<IdEntity> entities = new ArrayList<IdEntity>(); // 在这里,必须使用try catch finally语句。来确定会话正常关闭. // 否则,当操作数据库产生错误时,你可能需要重启mysql服务 try { // 查询Teacher表,注意:是Teacher ,而不是 teacher Query query = session.createQuery("from " + getFeaturedClass().getSimpleName()); // 预查询,只有在事务提交时,才进行查询操作 entities = query.list(); // 提交事务 transaction.commit(); // 捕获异常 } catch (HibernateException e) { // 如果事务执行异常,则回滚事务 if (null != transaction) { try { transaction.rollback(); } catch (TransactionException te) { te.printStackTrace(); } } // 打印异常 e.printStackTrace(); } finally { // 如果session处于开启状态,则关闭session if (session.isOpen()) { // 关闭会话 session.close(); } } return entities; } @SuppressWarnings("unchecked") public Collection<?> paginate(int page, int pageSize) { // 创建会话(这里的session也是会话的意思,我们以前接触的http中的session,处理的是用户与服务器的对话) Session session = getCurrentSession(); // 开启事务(使用缓冲池进行数据库的连接) Transaction transaction = session.beginTransaction(); Collection<IdEntity> entities = new ArrayList<IdEntity>(); // 在这里,必须使用try catch finally语句。来确定会话正常关闭. // 否则,当操作数据库产生错误时,你可能需要重启mysql服务 try { // 查询Teacher表,注意:是Teacher ,而不是 teacher String hql = "from " + getFeaturedClass().getSimpleName(); // 预查询,只有在事务提交时,才进行查询操作 entities = (ArrayList<IdEntity>) session.createQuery(hql) .setFirstResult(page) .setMaxResults(pageSize) .list(); // 提交事务 transaction.commit(); // 捕获异常 } catch (HibernateException e) { // 如果事务执行异常,则回滚事务 if (null != transaction) { try { transaction.rollback(); } catch (TransactionException te) { te.printStackTrace(); } } // 打印异常 e.printStackTrace(); } finally { // 如果session处于开启状态,则关闭session if (session.isOpen()) { // 关闭会话 session.close(); } } return entities; } } ``` 在TeacherDao中,实现抽象类中未实现的方法: ``` package com.mengyunzhi.javaee.dao; import com.mengyunzhi.javaee.entity.Teacher; public class TeacherDao extends AbstractDao { /** * */ private static final long serialVersionUID = 1L; @Override public Class<Teacher> getFeaturedClass() { // 返回Teacher实体类 return Teacher.class; } } ```