Spring DAO เทียบกับ Spring ORM และ Spring JDBC


103

ฉันกำลังใช้เทคโนโลยีการเข้าถึงข้อมูลที่ Spring รองรับและฉันสังเกตว่ามันกล่าวถึงตัวเลือกมากมายและฉันไม่แน่ใจเกี่ยวกับความแตกต่างระหว่างพวกเขา:

ตามที่ฉันเข้าใจ Spring JDBC มีเทมเพลตสำหรับการลดรหัสสำเร็จรูปสำหรับการเข้าถึงฐานข้อมูลด้วยวิธีการเดิม ๆ - คุณเขียนแบบสอบถาม SQL ของคุณเอง

Spring-ORM มีเทมเพลตที่เรียบง่ายสำหรับการเข้าถึงฐานข้อมูลผ่านเทคโนโลยี ORM เช่น Hibernate, My (i) Batis เป็นต้น

Spring-DAO ตามเว็บไซต์ของ Spring:

การสนับสนุน Data Access Object (DAO) ใน Spring มีวัตถุประสงค์เพื่อให้ง่ายต่อการทำงานกับเทคโนโลยีการเข้าถึงข้อมูลเช่น JDBC, Hibernate หรือ JDO ในลักษณะที่สอดคล้องกัน

ฉันค่อนข้างชัดเจนเกี่ยวกับ ORM กับ JDBC เนื่องจากมุ่งเป้าไปที่วิธีการต่างๆในการเข้าถึง DB แต่ Spring-DAO เป็นเพียงความสับสน!

ใครช่วยชี้แจงได้ไหมว่าอะไรคือความแตกต่างในสามสิ่งนี้? ควรเลือกใช้ในสถานการณ์ใด

นอกจากนี้ยังมีโครงการอื่นอีกSpring-DATA( http://projects.spring.io/spring-data/ ) ตอนนี้เป็นโครงการหลักสำหรับเทคโนโลยีการเข้าถึงข้อมูลทั้งหมดที่ Spring รองรับหรือเป็นเพียงชื่อใหม่สำหรับ Spring - ดาว?

คำตอบ:


162

นี่คือข้อมูลเบื้องต้นเกี่ยวกับเทคโนโลยีที่กล่าวถึง

ฤดูใบไม้ผลิ - ดาว

Spring-DAO ไม่ใช่โมดูลสปริงในความหมายที่เข้มงวด แต่เป็นอนุสัญญาที่ควรกำหนดให้คุณเขียน DAO และเขียนให้ดี ด้วยเหตุนี้จึงไม่มีอินเทอร์เฟซหรือการใช้งานหรือเทมเพลตในการเข้าถึงข้อมูลของคุณ เมื่อเขียน DAO คุณควรใส่คำอธิบายประกอบ@Repositoryเพื่อให้ข้อยกเว้นที่เชื่อมโยงกับเทคโนโลยีพื้นฐาน (JDBC, Hibernate, JPA ฯลฯ ) ได้รับการแปลเป็นDataAccessExceptionคลาสย่อยที่เหมาะสมอย่างสม่ำเสมอ

ตัวอย่างเช่นสมมติว่าคุณกำลังใช้ Hibernate และชั้นบริการของคุณจับHibernateExceptionเพื่อที่จะตอบสนอง ถ้าคุณเปลี่ยนไป JPA อินเตอร์เฟซ DAOs ของคุณไม่ควรเปลี่ยนแปลงและชั้นบริการจะยังคงรวบรวมกับบล็อกที่จับHibernateExceptionแต่คุณจะไม่เคยใส่บล็อกเหล่านี้เป็น DAOs ของคุณอยู่ในขณะนี้การขว้างปา PersistenceExceptionJPA โดยใช้@Repositoryใน DAO ของคุณมีข้อยกเว้นที่เชื่อมโยงกับเทคโนโลยีดังกล่าวได้รับการแปลเป็นฤดูใบไม้ผลิDataAccessException; ชั้นบริการของคุณตรวจจับข้อยกเว้นเหล่านี้และหากคุณตัดสินใจที่จะเปลี่ยนเทคโนโลยีการคงอยู่ Spring เดียวกันDataAccessExceptionsจะยังคงถูกโยนทิ้งเนื่องจาก Spring ได้แปลข้อยกเว้นดั้งเดิม

อย่างไรก็ตามโปรดทราบว่าสิ่งนี้มีการใช้งานที่ จำกัด ด้วยเหตุผลต่อไปนี้:

  1. โดยปกติคุณไม่ควรตรวจจับข้อยกเว้นการคงอยู่เนื่องจากผู้ให้บริการอาจย้อนกลับธุรกรรม (ขึ้นอยู่กับประเภทย่อยของข้อยกเว้นที่แน่นอน) ดังนั้นคุณจึงไม่ควรดำเนินการต่อด้วยเส้นทางอื่น
  2. ลำดับชั้นของข้อยกเว้นมักจะมีมากขึ้นในผู้ให้บริการของคุณมากกว่าที่ Spring มีให้และไม่มีการจับคู่ที่ชัดเจนจากผู้ให้บริการรายหนึ่งไปยังอีกรายหนึ่ง การอาศัยสิ่งนี้เป็นอันตราย อย่างไรก็ตามนี่เป็นความคิดที่ดีที่จะใส่คำอธิบายประกอบ DAO ของคุณด้วย@Repositoryเนื่องจากขั้นตอนการสแกนจะเพิ่มถั่วโดยอัตโนมัติ นอกจากนี้ Spring อาจเพิ่มคุณสมบัติที่เป็นประโยชน์อื่น ๆ ในคำอธิบายประกอบ

สปริง -JDBC

Spring-JDBC จัดเตรียมคลาส JdbcTemplate ซึ่งจะลบรหัสท่อประปาและช่วยให้คุณมีสมาธิกับแบบสอบถาม SQL และพารามิเตอร์ คุณต้องกำหนดค่าด้วย a DataSourceจากนั้นคุณสามารถเขียนโค้ดได้ดังนี้:

int nbRows = jdbcTemplate.queryForObject("select count(1) from person", Integer.class);

Person p = jdbcTemplate.queryForObject("select first, last from person where id=?", 
             rs -> new Person(rs.getString(1), rs.getString(2)), 
             134561351656L);

Spring-JDBC ยังมี JdbcDaoSupport ซึ่งคุณสามารถขยายเพื่อพัฒนา DAO ของคุณได้ โดยทั่วไปจะกำหนดคุณสมบัติ 2 อย่างคือ DataSource และ JdbcTemplate ที่ทั้งสองสามารถใช้เพื่อใช้วิธี DAO นอกจากนี้ยังมีตัวแปลข้อยกเว้นจากข้อยกเว้น SQL เพื่อสปริง DataAccessExceptions

หากคุณวางแผนที่จะใช้ jdbc ธรรมดานี่คือโมดูลที่คุณจะต้องใช้

สปริง - ออม

Spring-ORM เป็นโมดูลร่มที่ครอบคลุมเทคโนโลยีการคงอยู่มากมาย ได้แก่ JPA, JDO, Hibernate และ iBatis สำหรับแต่ละเทคโนโลยีเหล่านี้ Spring มีคลาสการรวมเพื่อให้แต่ละเทคโนโลยีสามารถใช้ตามหลักการกำหนดค่า Spring และผสานรวมกับการจัดการธุรกรรม Spring ได้อย่างราบรื่น

สำหรับแต่ละเทคโนโลยีการกำหนดค่าโดยพื้นฐานประกอบด้วยการฉีดDataSourceถั่วลงในถั่วบางชนิดSessionFactoryหรือEntityManagerFactoryอื่น ๆ สำหรับ JDBC บริสุทธิ์ไม่จำเป็นต้องมีคลาสการรวมดังกล่าว (นอกเหนือจาก JdbcTemplate) เนื่องจาก JDBC ต้องอาศัย DataSource เท่านั้น

หากคุณวางแผนที่จะใช้ ORM เช่น JPA หรือ Hibernate คุณไม่จำเป็นต้องใช้ spring-jdbc แต่มีเพียงโมดูลนี้

สปริง - ข้อมูล

Spring-Data เป็นโครงการร่มที่มี API ทั่วไปเพื่อกำหนดวิธีการเข้าถึงข้อมูล (คำอธิบายประกอบ DAO +) ในรูปแบบทั่วไปมากขึ้นซึ่งครอบคลุมทั้งแหล่งข้อมูล SQL และ NOSQL

แนวคิดเริ่มต้นคือการจัดหาเทคโนโลยีเพื่อให้นักพัฒนาเขียนอินเทอร์เฟซสำหรับ DAO (วิธีการค้นหา) และคลาสเอนทิตีด้วยวิธีที่ไม่เชื่อเรื่องพระเจ้าและอิงตามการกำหนดค่าเท่านั้น (คำอธิบายประกอบใน DAOs & entities + spring configuration ไม่ว่าจะเป็น xml- หรือ java) ตัดสินใจใช้เทคโนโลยีการใช้งานไม่ว่าจะเป็น JPA (SQL) หรือ redis, hadoop ฯลฯ (NOSQL)

หากคุณทำตามหลักการตั้งชื่อที่กำหนดโดยฤดูใบไม้ผลิสำหรับชื่อเมธอด finder คุณไม่จำเป็นต้องระบุสตริงการสืบค้นที่สอดคล้องกับวิธีการค้นหาสำหรับกรณีที่ง่ายที่สุด สำหรับสถานการณ์อื่น ๆ คุณต้องระบุสตริงการสืบค้นภายในคำอธิบายประกอบเกี่ยวกับวิธีการค้นหา

เมื่อโหลดบริบทของแอ็พพลิเคชัน spring จะจัดเตรียมพร็อกซีสำหรับอินเทอร์เฟซ DAO ซึ่งมีโค้ดสำเร็จรูปทั้งหมดที่เกี่ยวข้องกับเทคโนโลยีการเข้าถึงข้อมูลและเรียกใช้เคียวรีที่กำหนดค่าไว้

Spring-Data มุ่งเน้นไปที่เทคโนโลยีที่ไม่ใช่ SQL แต่ยังคงมีโมดูลสำหรับ JPA (เทคโนโลยี SQL เพียงตัวเดียว)

อะไรต่อไป

รู้ทั้งหมดนี้ตอนนี้คุณต้องตัดสินใจว่าจะเลือกอะไร ข่าวดีก็คือคุณไม่จำเป็นต้องตัดสินใจขั้นสุดท้ายสำหรับเทคโนโลยีนี้ นี่คือที่ที่ Spring power อยู่: ในฐานะนักพัฒนาคุณให้ความสำคัญกับธุรกิจเมื่อคุณเขียนโค้ดและถ้าคุณทำได้ดีการเปลี่ยนเทคโนโลยีพื้นฐานก็คือการใช้งานหรือการกำหนดค่ารายละเอียด

  1. กำหนดแบบจำลองข้อมูลด้วยคลาส POJO สำหรับเอนทิตีและรับ / ตั้งค่าวิธีการเพื่อแสดงแอตทริบิวต์เอนทิตีและความสัมพันธ์กับเอนทิตีอื่น แน่นอนคุณจะต้องใส่คำอธิบายประกอบคลาสเอนทิตีและฟิลด์ตามเทคโนโลยี แต่ตอนนี้ POJO ก็เพียงพอแล้วที่จะเริ่มต้นด้วย เพียงแค่มุ่งเน้นไปที่ข้อกำหนดทางธุรกิจในตอนนี้
  2. กำหนดอินเทอร์เฟซสำหรับ DAO ของคุณ 1 DAO ครอบคลุม 1 เอนทิตี แต่คุณไม่จำเป็นต้องมี DAO สำหรับแต่ละเอนทิตีเนื่องจากคุณควรจะโหลดเอนทิตีเพิ่มเติมได้โดยไปที่ความสัมพันธ์ กำหนดวิธีการค้นหาตามหลักการตั้งชื่อที่เข้มงวด
  3. ด้วยเหตุนี้บุคคลอื่นสามารถเริ่มทำงานกับเลเยอร์บริการได้โดยมีการล้อเลียนสำหรับ DAO ของคุณ
  4. คุณเรียนรู้เทคโนโลยีการคงอยู่ที่แตกต่างกัน (sql, no-sql) เพื่อค้นหาสิ่งที่เหมาะสมที่สุดสำหรับความต้องการของคุณและเลือกหนึ่งในนั้น ด้วยเหตุนี้คุณจึงใส่คำอธิบายประกอบเอนทิตีและนำ DAO ไปใช้ (หรือปล่อยให้ spring นำไปใช้ให้กับคุณหากคุณเลือกที่จะใช้ข้อมูลสปริง)
  5. หากความต้องการทางธุรกิจมีการเปลี่ยนแปลงและเทคโนโลยีการเข้าถึงข้อมูลของคุณไม่เพียงพอที่จะรองรับ (เช่นคุณเริ่มต้นด้วย JDBC และเอนทิตีไม่กี่แห่ง แต่ตอนนี้ต้องการโมเดลข้อมูลที่สมบูรณ์ยิ่งขึ้นและ JPA เป็นทางเลือกที่ดีกว่า) คุณจะต้องเปลี่ยนการใช้งาน ของ DAO ของคุณเพิ่มคำอธิบายประกอบบางส่วนในเอนทิตีของคุณและเปลี่ยนการกำหนดค่าสปริง (เพิ่มคำจำกัดความของ EntityManagerFactory) รหัสธุรกิจที่เหลือของคุณไม่ควรเห็นผลกระทบอื่น ๆ จากการเปลี่ยนแปลงของคุณ

หมายเหตุ: การจัดการธุรกรรม

Spring มี API สำหรับการจัดการธุรกรรม หากคุณวางแผนที่จะใช้สปริงสำหรับการเข้าถึงข้อมูลคุณควรใช้สปริงสำหรับการจัดการธุรกรรมด้วยเนื่องจากมันรวมเข้าด้วยกันได้เป็นอย่างดี สำหรับเทคโนโลยีการเข้าถึงข้อมูลแต่ละรายการที่รองรับโดย spring มีตัวจัดการธุรกรรมที่ตรงกันสำหรับธุรกรรมในพื้นที่หรือคุณสามารถเลือก JTA หากคุณต้องการธุรกรรมแบบกระจาย พวกเขาทั้งหมดใช้ API เดียวกันดังนั้น (อีกครั้ง) ทางเลือกเทคโนโลยีจึงเป็นเพียงการกำหนดค่าที่สามารถเปลี่ยนแปลงได้โดยไม่ส่งผลกระทบต่อรหัสธุรกิจอีกต่อไป

หมายเหตุ: เอกสาร Spring

ลิงก์ไปยังเอกสาร Spring ที่คุณกล่าวถึงค่อนข้างเก่า นี่คือเอกสารของรุ่นล่าสุด (4.1.6 ครอบคลุมทุกหัวข้อ):

Spring-data ไม่ได้เป็นส่วนหนึ่งของ Spring framework มีโมดูลทั่วไปที่คุณควรอ่านเพื่อทำความคุ้นเคยกับหลักการก่อน เอกสารสามารถพบได้ที่นี่:


ฉันขอขอบคุณคำตอบนี้โดยใช้คำว่า "ร่ม" ในคำอธิบายบางส่วนที่นี่ (เช่น Spring Data) โดยระบุว่ามีส่วนประกอบย่อย / โมดูลอยู่ภายใน (แทนที่จะเป็นร่มที่เจาะจงโดเมนมากกว่า) และการกล่าวถึง Spring Data มีประโยชน์มากในบริบทนี้แม้ว่าจะไม่ได้กล่าวถึงในคำถามก็ตาม
cellepo

ไม่มีspring-jdbcเครื่องมือที่มีประโยชน์อื่น ๆ ที่ไม่ได้กล่าวถึงในที่นี้? ตัวอย่างเช่นฉันพบว่าSimpleJdbcInsertสะอาดและมีประโยชน์มากสำหรับการใส่ทั้งแบบเข้าครั้งเดียวและแบบเป็นกลุ่ม (แน่นอนว่ามีขนาดที่เหมาะสม)
Nom1fan

3

Spring DAO ( D ata A ccess O bject): เป็นอ็อบเจ็กต์ที่ให้อินเทอร์เฟซนามธรรมกับกรอบการใช้งาน JDBC เช่น Spring DAO เป็น แนวคิดทั่วไปในการเข้าถึง JDBC และ Hibernate, MyBatis, JPA, JDO โดยใช้คลาส Support ของแต่ละคน และจัดทำลำดับชั้นข้อยกเว้นโดยทั่วไปโดยการกำหนด@Repositoryคำอธิบายประกอบ คำอธิบายประกอบนี้กำหนดให้ Spring container สำหรับการแปลข้อยกเว้นของ SQLจากSQLExceptionไปยังDataAccessExceptionลำดับชั้นของ กลยุทธ์การเข้าถึงข้อมูลแบบไม่เชื่อเรื่องพระเจ้าของ Spring

เช่นข้อยกเว้นเฉพาะของแพลตฟอร์มจะถูกจับแล้วโยนใหม่เป็นข้อยกเว้นการเข้าถึงข้อมูลที่ไม่ได้ตรวจสอบของ Spring


ฤดูใบไม้ผลิ JDBC : สำหรับ JDBC ธรรมดาที่เราใช้โมดูลนี้ซึ่งเป็นเพียงขึ้นอยู่กับการDataSourceเรียนและแม่แบบชอบJdbcTemplate, NamedParameterJdbcTemplate(ตัดJdbcTemplate) และSimpleJdbcTemplateเพื่อลดความกังวลตัดข้าม

public class EmployeeDao {  
private JdbcTemplate jdbcTemplate;  

public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {  
    this.jdbcTemplate = jdbcTemplate;  
}  

public int saveEmployee(Employee e){  
    return jdbcTemplate.update(query);  
}  
public int updateEmployee(Employee e){  
    return jdbcTemplate.update(query);  
}  
public int deleteEmployee(Employee e){  
       return jdbcTemplate.update(query);  
}  

}  

และใน Spring XML:

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
    <property name="dataSource" ref="dataSource"/>
</bean>

ฤดูใบไม้ผลิ JDBC ยังให้ JdbcDaoSupport, NamedParameterJdbcDaoSupport, SimpleJdbcDaoSupportซึ่งเป็นการสนับสนุน (เช่นสะดวก ) วิธีการขยายและพัฒนาของเราเองDAOอินเตอร์เฟซที่เป็นนามธรรมดังต่อไปนี้:

public interface EmployeeDao {

    public void saveEmployee(Employee emp);
}

public class EmployeeDaoImpl extends JdbcDaoSupport implements EmployeeDao{

    @Override
    public void saveEmployee(Employee emp) {

        Object[] inputs = new Object[] {emp.getName(), emp.getSalary(), emp.getDept()};
        getJdbcTemplate().update(query, inputs);
    }
}

และใน XML ฤดูใบไม้ผลิ:

<bean id="employeeDAO" class="EmployeeDaoImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>

Spring ORM:สำหรับการสนับสนุนเครื่องมือ ORM เช่น Hibernate, JPA, MyBatis ... รวม Spring ได้อย่างง่ายดายโดยการฉีดเข้าDataSourceกับคลาสต่อไปนี้และDaoSupportคลาสที่เกี่ยวข้อง

  • SessionFactory สำหรับไฮเบอร์เนต
  • EntityManagerFactory สำหรับ JPA
  • SqlSessionFactory สำหรับ MyBatis

1

spring-dao lib หยุดลงในเวอร์ชัน 2.0.8 (มกราคม 2008) คลาสใน spring-dao ถูกคัดลอกไปยัง spring-tx ดังนั้นหากคุณต้องการคลาสที่คุณพบใน spring-dao ให้เพิ่มการอ้างอิงกับspring-txแทน ( ที่มา )


0

คุณสามารถสร้างอินเตอร์เฟซที่ชอบSomeObjectDaoแล้วสร้างการใช้งานที่แตกต่างกันของอินเตอร์เฟซนี้เช่น,JdbcSomeObjectDao HibernateSomeObjectDaoจากนั้นในSomeObjectServiceชั้นเรียนของคุณคุณจะดำเนินการบนSomeObjectDaoอินเทอร์เฟซและฉีดหนึ่งในการใช้งานที่เป็นรูปธรรม ดังนั้นการใช้งานแต่ละครั้งSomeObjectDaoจะซ่อนรายละเอียดไม่ว่าคุณจะใช้ JDBC หรือ ORM เป็นต้น

โดยปกติ JDBC และการใช้งาน ORM ที่แตกต่างกันจะทำให้เกิดข้อยกเว้นที่แตกต่างกัน การสนับสนุน DAOของ Spring สามารถจับคู่ข้อยกเว้นเฉพาะเทคโนโลยีที่แตกต่างกันเหล่านั้นกับข้อยกเว้น Spring DAO ทั่วไปได้ ดังนั้นคุณจึงแยกออกจากการใช้งานจริงมากขึ้น นอกจากนี้การสนับสนุน DAOของ Spring ยังมีชุด*DataSupportคลาสนามธรรมซึ่งช่วยได้มากขึ้นในการพัฒนา DAO นอกจากการนำSomeObjectDaoอินเทอร์เฟซไปใช้แล้วคุณสามารถขยาย*DataSupportคลาสของ Spring ได้อีกหนึ่งคลาส


ดังนั้นคุณหมายถึงว่า spring-dao แยกข้อยกเว้นเฉพาะสำหรับ Hibernate / JDO / JDBC และให้ชุดข้อยกเว้นมาตรฐาน? มีtemplatesการเข้าถึงฐานข้อมูลหรือไม่? หรือเป็นเพียงนามธรรมที่จะใช้กับส่วนประกอบสปริงอื่น ๆ ? เช่นเป็นไปได้ไหมที่จะเขียนโค้ดที่ใช้เฉพาะ spring-dao เพื่อเข้าถึง db (โดยไม่ใช้ spring-jdbc, spring-orm, hibernate หรือ framework อื่น ๆ )

0

เป็นข้อมูลเพิ่มเติม ฉันขอแนะนำให้คุณใช้ Spring Data JPA การใช้คำอธิบายประกอบเช่น @Repository, @Service ฉันแสดงตัวอย่าง:

@Repository("customerEntitlementsRepository")
public interface CustomerEntitlementsRepository extends CrudRepository<BbsExerul, BbsExerulPK> {

  @Query(value = "SELECT " + "CONTRACT_NUMBER, EXECUTIVE_NUMBER, " + "GROUP_VALUE, " + "CODE, "
      + "SUBCODE, " + "CURRENCY " + "FROM BBS_EXERUL " + "WHERE CONTRACT_NUMBER =:clientId AND "
      + "EXECUTIVE_NUMBER =:representativeId", nativeQuery = true)
  Collection<CustomerEntitlementsProjection> getFieldsExerul(@Param("clientId") String clientId,
      @Param("representativeId") String representativeId);

}

โดย CustomerEntitlementsProjection คือ Spring projection ที่เชื่อมโยงกับเอนทิตีของคุณหรือ DTO pojo

@Projection(name = "customerEntitlementsProjection", types = { BbsExerul.class })
public interface CustomerEntitlementsProjection {

  String getContractNumber();

  String getExecutiveNumber();

1
โปรดจัดรูปแบบรหัสของคุณในบล็อกโค้ดเพื่อให้สามารถอ่านได้
CertainPerformance
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.