OOP、MVC(Java)中实体类数据库调用的实践困惑
为什么不在实体类中直接写数据库调用?(附更优方案)
嘿,这个问题问得特别到位——刚接触MVC和分层开发的时候,很多人都会疑惑“为啥不能直接在Monkey、Banana这类实体里写存库逻辑”,我当初刚入行时也这么干过,后来踩了一堆坑才明白其中的道理!
直接在实体类写数据库调用的问题
- 违反单一职责原则:实体类的核心职责是代表业务对象,比如
Monkey要描述猴子的属性(名字、年龄)和业务行为(吃香蕉、爬树),而数据库操作属于“数据持久化”的职责。把两者混在一起,一个类既要管“是什么”,又要管“怎么存”,以后改业务逻辑或者换数据库时,你得把所有实体类都改一遍,维护成本爆炸。 - 耦合度太高:实体类会和具体的数据库技术强绑定(比如你用了JDBC的代码在
Monkey里),这意味着这个类离不开JDBC,甚至离不开当前的数据库类型。想写单元测试都麻烦——测试猴子吃香蕉的逻辑,居然还要启动数据库才能跑通?完全没必要。 - 代码重复冗余:每个实体类都要写
save()、update()、delete()这些几乎一样的数据库方法,重复代码一大堆。哪天要改数据库连接配置,或者换个ORM框架(比如从JDBC换成MyBatis),你得逐个修改所有实体类,想想都头大。
更优的处理方式:分层拆分,用数据访问层(DAO/DBHandler)
核心思路是关注点分离,把数据库操作从实体类里抽出来,单独放到专门的组件里——也就是你提到的DBHandler,或者更常见的DAO(Data Access Object,数据访问对象)层。
具体分层逻辑(结合MVC)大概是这样:
- 实体层(Entity):就是你的
Monkey、Banana类,只负责封装数据和纯业务逻辑,完全不碰数据库相关代码。 - DAO层(数据访问层):专门处理数据库交互,每个实体对应一个DAO(比如
MonkeyDAO、BananaDAO),所有的存库、查库、更新逻辑都写在这里。 - 业务逻辑层(Service):调用DAO层完成业务流程(比如“猴子吃香蕉后,更新猴子的状态和香蕉的库存”),Controller层再调用Service层处理请求。
举个简单的代码示例:
实体类(Monkey)
public class Monkey { private String name; private int age; // getter、setter方法 public void eatBanana(Banana banana) { // 纯业务逻辑:猴子吃香蕉,香蕉数量减1 banana.setQuantity(banana.getQuantity() - 1); } }
DAO类(MonkeyDAO)
public class MonkeyDAO { // 保存猴子到数据库 public void saveMonkey(Monkey monkey) { // 这里写数据库操作代码,比如JDBC、MyBatis调用 String sql = "INSERT INTO monkey(name, age) VALUES (?, ?)"; // 执行SQL的逻辑... } // 根据ID查询猴子 public Monkey getMonkeyById(int id) { // 查询数据库并返回Monkey实例的逻辑... return new Monkey(); } }
这种方式的好处
- 低耦合:实体类和数据库完全解耦,以后换数据库(比如从MySQL换成MongoDB),只需要修改DAO层的代码,实体类根本不用动。
- 易测试:测试
Monkey的eatBanana方法时,直接new一个Monkey和Banana就能跑,完全不需要依赖数据库,单元测试变得简单高效。 - 代码复用:可以写通用的BaseDAO封装CRUD逻辑,所有实体的DAO都能继承复用,减少重复代码。
- 维护方便:以后数据库操作出问题,直接找DAO层就行,不用在一堆实体类里翻找,定位问题更快。
说白了,这种分层思想就是让每个组件只做自己最擅长的事,各司其职,代码结构更清晰,也更利于项目的长期维护和扩展。
内容的提问来源于stack exchange,提问作者EliiTryToLearn
相关产品推荐
相关产品推荐

