ORM用於複雜CRUD,SQL用於大規模讀取
現在人們已經認識到Hibernate等ORM有一定的侷限性,在CQRS讀寫分離的架構中,ORM主要用於命令寫操作,進行復雜的增刪改查CRUD;而SQL用於查詢讀操作。
下面是Spring程式碼部分:
Hibernate ORM, jOOQ, HikariCP, Transactions, and S一文分享了他們在自己的NeighborLink專案中如何實踐這個原則。
經驗如下:
1.使用明確的讀寫分離. 實體用於CRUD, 簡單DTO用於查詢結果.
2.讀寫兩邊使用同樣物件,而不是維護多個模型,經常會在SQL結果中複用實體物件。
2.透過繼承實現分層目標,物件的基礎層包含物件的基本必要欄位,然後分別有實體和DTO繼承它。或者使用DTO作為基礎,實體繼承DTO。
在具體技術上,CRUD採取Hibernate,查詢是JOOQ,JOOQ能夠以Java方式編寫SQL(DSL),而且可以根據資料庫中資料表結構自動產生元模型,如果資料表結構變化,產生的元模型會隨著改變,這樣編譯時會出錯。元模型和DSL都會以資料庫本地語言最佳化地和資料庫打交道。
具體程式碼如下,前端使用的Spring。 將DataSource 和 HibernateTransactionManager 分享給所有DB互動, 包括ORM, jOOQ, 和直接的JDBC!
Maven配置的庫包如下:
<build> <plugins> ... <plugin> <groupId>org.jooq</groupId> <artifactId>jooq-codegen-maven</artifactId> <version>${jooq.version}</version> <executions> <execution> <goals> <goal>generate</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-codegen</artifactId> <version>${jooq.version}</version> </dependency> </dependencies> <configuration> <jdbc> <driver>com.mysql.jdbc.Driver</driver> <url>jdbc:mysql://[HOST]:[PORT]/[DB NAME]</url> <user>[USER]</user> <password>[PASSWORD]</password> </jdbc> <generator> <name>org.jooq.util.DefaultGenerator</name> <database> <name>org.jooq.util.mysql.MySQLDatabase</name> <includes>.*</includes> <excludes></excludes> <inputSchema>[DB NAME]</inputSchema> </database> <target> <packageName>org.threeriverdev.neighborlink.query</packageName> <directory>target/generated-sources/jooq</directory> </target> </generator> </configuration> </plugin> ... </build> <dependencies> <!-- Spring framework --> ... <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> ... <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <!-- DataSource --> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>2.4.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version> </dependency> <!-- jOOQ --> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq</artifactId> <version>${jooq.version}</version> </dependency> <dependency> <groupId>org.jooq</groupId> <artifactId>jooq-meta</artifactId> <version>${jooq.version}</version> </dependency> ... </dependencies> <p class="indent"> |
下面是Spring程式碼部分:
@Configuration @EnableWebMvc @EnableTransactionManagement @ComponentScan public class AppConfig { @Autowired private Environment env; @Autowired private ConfigService configService; ... @Bean(destroyMethod = "close") public DataSource dataSource() { String dbHost; String dbPort; String dbName; String dbUsername; String dbPassword; if (configService.isProduction()) { // We're in a production environment. dbHost = "localhost"; dbPort = "3306"; dbName = configService.getConfig().getDatabase().getName(); dbUsername = configService.getConfig().getDatabase().getUsername(); dbPassword = configService.getConfig().getDatabase().getPassword(); } else { // Local dev or unit test. dbHost = "[HOST]"; dbPort = "[PORT]"; dbName = "[DB NAME]"; dbUsername = "[USER]"; dbPassword = "[PASSWORD]"; } final String url = new StringBuilder() .append("jdbc:mysql://") .append(dbHost) .append(":") .append(dbPort) .append("/") .append(dbName) .toString(); HikariDataSource dataSource = new HikariDataSource(); ...[HikariCP options] MysqlDataSource mysqlDataSource = new MysqlDataSource(); mysqlDataSource.setURL(url); mysqlDataSource.setUser(dbUsername); mysqlDataSource.setPassword(dbPassword); ...[MySQL-specific options] dataSource.setDataSource(mysqlDataSource); return dataSource; } // HIBERNATE @Bean public LocalSessionFactoryBean sessionFactory() { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); sessionFactory.setDataSource(dataSource()); sessionFactory.setHibernateProperties(hibernateProperties()); List<String> packages = new ArrayList<String>(); packages.add("org.threeriverdev.neighborlink.entity.core"); ... sessionFactory.setPackagesToScan(packages.toArray(new String[packages.size()])); return sessionFactory; } @Bean public HibernateTransactionManager transactionManager() { HibernateTransactionManager txManager = new HibernateTransactionManager(); txManager.setSessionFactory(sessionFactory().getObject()); txManager.setDataSource(dataSource()); return txManager; } private Properties hibernateProperties() { final Properties properties = new Properties(); ...[Add all "hibernate.*" specific properties -- dialect, etc.] return properties; } // JOOQ @Bean public TransactionAwareDataSourceProxy transactionAwareDataSource() { return new TransactionAwareDataSourceProxy(dataSource()); } @Bean public DataSourceConnectionProvider connectionProvider() { return new DataSourceConnectionProvider(transactionAwareDataSource()); } @Bean() public DSLContext jooq() { // Generated source assumes the development DB. Dynamically change it to the production DB name. String dbName; if (configService.isProduction()) { // We're in a production environment. dbName = configService.getConfig().getDatabase().getName(); } else { // Local dev or unit test. dbName = "[SANDBOX DB NAME]"; } // The DB name used in the generated DSL (see the Maven plugin use) will not be the same as // the production DB, unless running in a local dev env! withSchemata allows us // to override that during runtime. Settings settings = new Settings().withRenderMapping( new RenderMapping().withSchemata(new MappedSchema().withInput("[SANDBOX DB NAME]").withOutput(dbName))); return DSL.using(connectionProvider(), SQLDialect.MYSQL, settings); } } <p class="indent"> |
相關文章
- DoytoQuery:用於CRUD的Java第二代ORM框架JavaORM框架
- 對於複雜系統只能採用模擬性建模? - Cilliers
- 大資料應用於智慧交通產業發展規模分析大資料產業
- Nature子刊,香港浸大、英偉達團隊多模態深度語言模型,用於複雜的宏基因組研究模型
- 關於程式碼複用
- 為NProgress增加模態層,更完美的應用於複雜網頁的細長進度條網頁
- 基於AWS雲服務的大資料與大規模計算的應用架構大資料應用架構
- SpringBoot 複雜配置資訊讀取Spring Boot
- Scala在Databricks的大規模應用
- 【譯】關於React Native在專業用於多種規模專案後的思考React Native
- 關於計算時間複雜度和空間複雜度時間複雜度
- 英政府IBM測試安全Linux 用於複雜商業環境(轉)IBMLinux
- 如何基於 Channel 實現多路複用
- 基於CMS的元件複用實踐元件
- 關於軟體複用的思考 (轉)
- 如何將模組化應用於 SQLSQL
- 百億節點、毫秒級延遲,攜程金融基於 NebulaGraph 的大規模圖應用實踐
- React、Redux與複雜業務元件的複用ReactRedux元件
- Kubernetes用於多雲、混合雲要注意基礎設施的複雜性
- SQL、Excel都沒用!再複雜的報表,用對工具就能統統解決SQLExcel
- SQL 複雜查詢SQL
- SQL複雜查詢SQL
- 實踐ORM,建立基於Grove的.NET應用程式(二) (轉)ORM
- 用程式碼複雜度分析風險複雜度
- .NET 5 ORM 八大實用技巧 乾貨 - SqlSugar ORMORMSqlSugar
- 適用於SQL Server生產環境DBA的七大技巧SQLServer
- 資訊化建設中的 複雜度 規模 度量問題複雜度
- Hibernate對於複雜查詢好用嗎?
- MyBatis SQL處理大於、小於號MyBatisSQL
- 基於規則的應用例項——流
- 關於ORM實現ORM
- 埠複用大揭密
- Mechanize庫,用於模擬瀏覽器行為瀏覽器
- 用資訊科技打造大規模定製的生產模式模式
- 【原】關於資料倉儲中複雜報表SQL語句的寫法SQL
- 基於viper的配置讀取
- 是否有用於建立簡單CRUD應用的開源工具? - ycombinator開源工具
- 乾貨分享!手把手教你構建用於文字聚類任務的大規模、高質量語料聚類