首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 留言板教學(十):Hibernate 整合與頁面調整

     編輯:Java 相關知識

本系列最終篇,展示如何將 Hibernate ORM 引入留言板專案,替換手寫 JDBC 實現,大幅簡化 DAO/Service 代碼,並說明頁面層面的微調。

Hibernate 核心配置

Hibernate 配置截圖

hibernate.cfg.xml 關鍵配置

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/msgboard?useSSL=false</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">123456</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.hbm2ddl.auto">update</property>
    <property name="hibernate.current_session_context_class">thread</property>
    <mapping class="com.example.model.Message"/>
    <mapping class="com.example.model.User"/>
  </session-factory>
</hibernate-configuration>

實體類別加註解

@Entity @Table(name = "message_board")
public class Message {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(name = "parent_id") private Integer parentId;
    @Column(name = "user_id") private Integer userId;
    private String title;
    @Lob private String content;
    @Column(name = "post_time") private Date postTime;
    private Integer status;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", insertable = false, updatable = false)
    private User user;

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @OrderBy("postTime ASC")
    private List<Message> replies;

    @Transient private Integer replyCount; // 非持久化屬性
    // getter/setter 略
}

@Entity @Table(name = "users")
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String username;
    private String password;
    private String email;
    @Column(name = "reg_time") private Date regTime;
    // getter/setter 略
}

DAO 層極簡實現


@Repository
public class MessageDao {
    @Autowired private SessionFactory sessionFactory;
    private Session getSession() { return sessionFactory.getCurrentSession(); }

    public void save(Message m) { getSession().save(m); }
    public void update(Message m) { getSession().update(m); }
    public void deleteById(Integer id) { 
        Message m = getSession().get(Message.class, id);
        if (m != null) m.setStatus(0); // 軟刪除
    }
    public Message findById(Integer id) { return getSession().get(Message.class, id); }

    @SuppressWarnings("unchecked")
    public List<Message> findTopics(int offset, int limit) {
        return getSession().createQuery(
            "FROM Message WHERE parentId = 0 AND status = 1 ORDER BY postTime DESC")
            .setFirstResult(offset).setMaxResults(limit).list();
    }
    public long countTopics() {
        return (Long) getSession().createQuery(
            "SELECT COUNT(*) FROM Message WHERE parentId = 0 AND status = 1").uniqueResult();
    }
}

Service 層簡化


@Service @Transactional
public class MessageServiceImpl implements MessageService {
    @Autowired private MessageDao messageDao;
    @Autowired private UserDao userDao;

    @Override
    public void postTopic(Integer userId, String title, String content) {
        Message m = new Message();
        m.setParentId(0); m.setUserId(userId); m.setTitle(title); m.setContent(content);
        m.setPostTime(new Date()); m.setStatus(1);
        messageDao.save(m);
    }

    @Override
    public PageBean<Message> findTopics(int pageNo, int pageSize) {
        long total = messageDao.countTopics();
        List<Message> list = messageDao.findTopics((pageNo-1)*pageSize, pageSize);
        // 回覆數可用 @Formula 或子查詢優化,此處簡單遍歷
        for (Message m : list) m.setReplyCount(countDirectReplies(m.getId()));
        return new PageBean<>(pageNo, pageSize, total, list);
    }
    // 其他方法同理極簡...
}

頁面層微調

  • JSP/JSTL 頁面零修改:Controller 仍傳遞 PageBean<Message>、Message、List<Message>,視圖層完全不知後端已換 ORM。
  • 若需在列表頁顯示回覆數,可在 Message 加 @Formula("(SELECT COUNT(*) FROM message_board WHERE parent_id = id AND status = 1)") 由 Hibernate 自動查詢,避免 N+1 問題。
  • 分頁參數 setFirstResult/setMaxResults 由 Hibernate 翻譯為資料庫原生 LIMIT,效能等同手寫 SQL。

Hibernate vs 手寫 JDBC 總結

維度手寫 JDBCHibernate
代碼量大(CRUD 模板、映射、資源管理)極少(註解+幾行 HQL)
SQL 控制力完全掌控可通過 HQL/Native SQL 微調
學習曲線低中(需懂 Session、事務、延遲加載)
效能調優手動索引、SQL 調優二級快取、批次抓取、@Formula、延遲加載策略
遷移成本無需重寫 DAO/實體,Service/Controller 不動

系列總結

十篇教學完整走過:

  1. 資料庫設計與 POPO
  2. 列表頁(JSTL / Scriptlet 對比)
  3. 回覆頁(JSTL / Scriptlet 對比)
  4. Service 介面與 JDBC 實現
  5. 發文頁(JSTL / Scriptlet 對比)
  6. Hibernate 整合

核心最佳實踐:介面隔離實現、JSTL/EL 消除 Scriptlet、參數化 SQL 防注入、分頁下推資料庫、軟刪除保留歷史、CSRF/XSS 防護、事務註解管理。這套架構可直接作為中小型 Java Web 專案的起始模板。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved