├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── archunit-start ├── .gitignore ├── build.gradle ├── docs │ └── InfrastructureLayer.puml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sight │ │ │ └── archunitstart │ │ │ ├── ArchunitStartApplication.java │ │ │ ├── controller │ │ │ ├── CamelUrlController.java │ │ │ └── InheritanceDtoController.java │ │ │ ├── domain │ │ │ ├── actor │ │ │ │ ├── .gitkeep │ │ │ │ └── model │ │ │ │ │ ├── ActorEntity.java │ │ │ │ │ └── ActorRepository.java │ │ │ └── film │ │ │ │ ├── .gitkeep │ │ │ │ └── model │ │ │ │ ├── FilmActorEntity.java │ │ │ │ └── FilmActorId.java │ │ │ ├── dto │ │ │ ├── Actor.java │ │ │ └── ActorExtension.java │ │ │ ├── enitty │ │ │ ├── AddressEntity.java │ │ │ ├── CategoryEntity.java │ │ │ ├── CityEntity.java │ │ │ ├── CountryEntity.java │ │ │ ├── CustomerEntity.java │ │ │ ├── FilmCategoryEntity.java │ │ │ ├── FilmCategoryId.java │ │ │ ├── FilmEntity.java │ │ │ ├── FilmTextEntity.java │ │ │ ├── InventoryEntity.java │ │ │ ├── LanguageEntity.java │ │ │ ├── PaymentEntity.java │ │ │ ├── RentalEntity.java │ │ │ ├── StaffEntity.java │ │ │ └── StoreEntity.java │ │ │ └── service │ │ │ └── ActorService.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── sight │ └── archunitstart │ ├── ControllerArchUnitTest.java │ ├── DddDirectoryTest.java │ ├── JpaEntityArchUnitTest.java │ ├── ProjectArchitectureTest.java │ └── config │ └── ArchitectureTest.java ├── dependent-subquery ├── .gitignore ├── application │ ├── .gitignore │ ├── build.gradle │ ├── jooq.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sight │ │ │ │ └── application │ │ │ │ ├── DependentSubqueryApplication.java │ │ │ │ ├── app │ │ │ │ ├── domain │ │ │ │ │ └── board │ │ │ │ │ │ ├── BoardRepository.java │ │ │ │ │ │ ├── BoardService.java │ │ │ │ │ │ ├── type │ │ │ │ │ │ ├── BoardTypeRepository.java │ │ │ │ │ │ └── BoardTypeService.java │ │ │ │ │ │ └── user │ │ │ │ │ │ ├── UserRepository.java │ │ │ │ │ │ └── UserService.java │ │ │ │ └── util │ │ │ │ │ └── RandomUtil.java │ │ │ │ ├── config │ │ │ │ ├── datasource │ │ │ │ │ └── DatasourceConfig.java │ │ │ │ └── jooq │ │ │ │ │ ├── BaseJooqRepository.java │ │ │ │ │ ├── ExceptionTranslator.java │ │ │ │ │ ├── JooqConfig.java │ │ │ │ │ ├── PerformanceListener.java │ │ │ │ │ └── TextSearchWildcard.java │ │ │ │ └── web │ │ │ │ ├── BoardRegisterRequest.java │ │ │ │ ├── BoardTypeRegisterRequest.java │ │ │ │ └── UserRegisterRequest.java │ │ └── resources │ │ │ ├── application-test.properties │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── sight │ │ └── application │ │ ├── config │ │ ├── AppProfile.java │ │ ├── IntegrationTest.java │ │ ├── JooqRepoTest.java │ │ └── jooq │ │ │ └── JooqTestConfig.java │ │ └── domain │ │ └── DataGenerationTest.java ├── build.gradle ├── docker-compose.yml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jooq-custom │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── jooq │ │ └── custom │ │ └── generator │ │ └── JPrefixGeneratorStrategy.java ├── jooq-entity │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── sight │ │ ├── entity │ │ ├── AppUser.java │ │ ├── Board.java │ │ ├── BoardType.java │ │ └── common │ │ │ └── HistoryRequiredEntity.java │ │ └── naming │ │ └── QuotedPhysicalNamingStrategy.java └── settings.gradle ├── galera-cluster-mariadb ├── .gitignore ├── doc_img │ ├── GALERA_1.PNG │ ├── SELF_LEAVE.PNG │ ├── first-comitters-win.png │ ├── first-comitters-win_2.png │ ├── ist.PNG │ ├── 마스터_1.PNG │ ├── 마스터_2.PNG │ └── 마스터_3.PNG ├── docker-compose.yml └── infra │ └── mariadb │ ├── config │ └── my.cnf │ ├── master-4 │ └── volume │ │ └── .gitkeep │ ├── master-5 │ └── volume │ │ └── .gitkeep │ └── sql │ ├── ddl.sql │ ├── seed.sql │ └── wsrep_status.sql ├── jooq-advanced ├── .gitignore ├── README.md ├── build.gradle ├── docker-compose.yml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── infra │ ├── .gitkeep │ └── mysql │ │ ├── init │ │ ├── ddl.sql │ │ └── seed.sql │ │ └── volumes │ │ └── .gitkeep ├── jooq-custom │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── jooq │ │ └── custom │ │ └── generator │ │ └── JPrefixGeneratorStrategy.java ├── jooq.gradle ├── settings.gradle └── src │ ├── http │ ├── author.http │ └── http-client.env.json │ ├── main │ ├── java │ │ └── com │ │ │ └── sightstudio │ │ │ └── jooq │ │ │ ├── JooqAdvancedApplication.java │ │ │ ├── app │ │ │ ├── domain │ │ │ │ ├── author │ │ │ │ │ ├── Author.java │ │ │ │ │ ├── AuthorBookDto.java │ │ │ │ │ ├── AuthorDto.java │ │ │ │ │ ├── AuthorRepository.java │ │ │ │ │ └── AuthorService.java │ │ │ │ └── book │ │ │ │ │ ├── BookDto.java │ │ │ │ │ └── BookRepository.java │ │ │ └── web │ │ │ │ ├── controller │ │ │ │ └── author │ │ │ │ │ └── AuthorController.java │ │ │ │ └── request │ │ │ │ ├── AuthorBulkRegisterRequest.java │ │ │ │ ├── AuthorRegisterRequest.java │ │ │ │ └── AuthorSearchRequest.java │ │ │ └── config │ │ │ ├── datasource │ │ │ └── DatasourceConfig.java │ │ │ └── jooq │ │ │ ├── BaseJooqRepository.java │ │ │ ├── ExceptionTranslator.java │ │ │ ├── JooqConfig.java │ │ │ ├── PerformanceListener.java │ │ │ └── TextSearchWildcard.java │ └── resources │ │ ├── application-test.properties │ │ └── application.properties │ └── test │ └── java │ └── com │ └── sightstudio │ └── jooq │ ├── JooqWithEntityApplicationTests.java │ ├── config │ ├── AppProfile.java │ ├── IntegrationTest.java │ ├── JooqRepoTest.java │ └── jooq │ │ └── JooqTestConfig.java │ └── domain │ ├── author │ └── AuthorRepoTest.java │ └── book │ └── BookRepoTest.java ├── jooq-codegen-with-entity ├── .gitignore ├── application │ ├── .gitignore │ ├── build.gradle │ ├── jooq.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sight │ │ │ │ └── application │ │ │ │ ├── DependentSubqueryApplication.java │ │ │ │ ├── app │ │ │ │ ├── dco │ │ │ │ │ └── OrderBy.java │ │ │ │ ├── domain │ │ │ │ │ └── board │ │ │ │ │ │ ├── BoardDetailDto.java │ │ │ │ │ │ ├── BoardRepository.java │ │ │ │ │ │ ├── BoardService.java │ │ │ │ │ │ ├── BoardSqlEdit.java │ │ │ │ │ │ ├── BoardSqlSearch.java │ │ │ │ │ │ ├── type │ │ │ │ │ │ ├── BoardTypeRepository.java │ │ │ │ │ │ └── BoardTypeService.java │ │ │ │ │ │ └── user │ │ │ │ │ │ ├── UserRepository.java │ │ │ │ │ │ └── UserService.java │ │ │ │ ├── dto │ │ │ │ │ └── OffsetPageSqlSearch.java │ │ │ │ └── util │ │ │ │ │ └── RandomUtil.java │ │ │ │ ├── config │ │ │ │ ├── datasource │ │ │ │ │ └── DatasourceConfig.java │ │ │ │ └── jooq │ │ │ │ │ ├── BaseJooqRepository.java │ │ │ │ │ ├── ExceptionTranslator.java │ │ │ │ │ ├── JooqConfig.java │ │ │ │ │ ├── PerformanceListener.java │ │ │ │ │ ├── TextSearchWildcard.java │ │ │ │ │ └── conditional │ │ │ │ │ ├── JooqDateTimeConditional.java │ │ │ │ │ ├── JooqListConditional.java │ │ │ │ │ ├── JooqNumberConditional.java │ │ │ │ │ ├── JooqSqlConditional.java │ │ │ │ │ └── JooqTextConditional.java │ │ │ │ └── web │ │ │ │ ├── BoardRegisterRequest.java │ │ │ │ ├── BoardTypeRegisterRequest.java │ │ │ │ └── UserRegisterRequest.java │ │ └── resources │ │ │ ├── application-test.properties │ │ │ ├── application.properties │ │ │ ├── db-init.sql │ │ │ └── example-query.sql │ │ └── test │ │ └── java │ │ └── com │ │ └── sight │ │ └── application │ │ ├── config │ │ ├── AppProfile.java │ │ ├── IntegrationTest.java │ │ ├── JooqRepoTest.java │ │ └── jooq │ │ │ └── JooqTestConfig.java │ │ ├── dataGen │ │ └── DataGenerationTest.java │ │ └── domain │ │ └── board │ │ └── BoardRepositoryTest.java ├── build.gradle ├── docker-compose.yml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jooq-custom │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── jooq │ │ └── custom │ │ └── generator │ │ └── JPrefixGeneratorStrategy.java ├── jooq-entity │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── sight │ │ ├── entity │ │ ├── AppUser.java │ │ ├── Board.java │ │ ├── BoardType.java │ │ └── common │ │ │ └── HistoryRequiredEntity.java │ │ └── naming │ │ └── QuotedPhysicalNamingStrategy.java └── settings.gradle ├── jooq-sight-demo ├── .gitignore ├── README.md ├── application-dsl-by-jpa │ ├── .gitignore │ ├── build.gradle │ ├── jooq-codegen-jpa.gradle │ └── src │ │ ├── generated │ │ └── jooq │ │ │ └── jooq_dsl │ │ │ ├── AbstractSpringDAOImpl.java │ │ │ ├── DefaultCatalog.java │ │ │ ├── DefaultSchema.java │ │ │ ├── Keys.java │ │ │ ├── Tables.java │ │ │ └── tables │ │ │ ├── JActor.java │ │ │ ├── JAddress.java │ │ │ ├── JCategory.java │ │ │ ├── JCity.java │ │ │ ├── JCountry.java │ │ │ ├── JCustomer.java │ │ │ ├── JFilm.java │ │ │ ├── JFilmactor.java │ │ │ ├── JFilmcategory.java │ │ │ ├── JFilmtext.java │ │ │ ├── JInventory.java │ │ │ ├── JLanguage.java │ │ │ ├── JPayment.java │ │ │ ├── JRental.java │ │ │ ├── JStaff.java │ │ │ ├── JStore.java │ │ │ ├── daos │ │ │ ├── ActorDao.java │ │ │ ├── AddressDao.java │ │ │ ├── CategoryDao.java │ │ │ ├── CityDao.java │ │ │ ├── CountryDao.java │ │ │ ├── CustomerDao.java │ │ │ ├── FilmDao.java │ │ │ ├── FilmactorDao.java │ │ │ ├── FilmcategoryDao.java │ │ │ ├── FilmtextDao.java │ │ │ ├── InventoryDao.java │ │ │ ├── LanguageDao.java │ │ │ ├── PaymentDao.java │ │ │ ├── RentalDao.java │ │ │ ├── StaffDao.java │ │ │ └── StoreDao.java │ │ │ ├── pojos │ │ │ ├── JActor.java │ │ │ ├── JAddress.java │ │ │ ├── JCategory.java │ │ │ ├── JCity.java │ │ │ ├── JCountry.java │ │ │ ├── JCustomer.java │ │ │ ├── JFilm.java │ │ │ ├── JFilmactor.java │ │ │ ├── JFilmcategory.java │ │ │ ├── JFilmtext.java │ │ │ ├── JInventory.java │ │ │ ├── JLanguage.java │ │ │ ├── JPayment.java │ │ │ ├── JRental.java │ │ │ ├── JStaff.java │ │ │ └── JStore.java │ │ │ └── records │ │ │ ├── JActorRecord.java │ │ │ ├── JAddressRecord.java │ │ │ ├── JCategoryRecord.java │ │ │ ├── JCityRecord.java │ │ │ ├── JCountryRecord.java │ │ │ ├── JCustomerRecord.java │ │ │ ├── JFilmRecord.java │ │ │ ├── JFilmactorRecord.java │ │ │ ├── JFilmcategoryRecord.java │ │ │ ├── JFilmtextRecord.java │ │ │ ├── JInventoryRecord.java │ │ │ ├── JLanguageRecord.java │ │ │ ├── JPaymentRecord.java │ │ │ ├── JRentalRecord.java │ │ │ ├── JStaffRecord.java │ │ │ └── JStoreRecord.java │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── sight │ │ │ └── application │ │ │ └── jpa │ │ │ ├── JooqJpaDSLDemoApplication.java │ │ │ └── config │ │ │ ├── datasource │ │ │ └── DatasourceConfig.java │ │ │ ├── jooq │ │ │ ├── ExceptionTranslator.java │ │ │ ├── JooqConfig.java │ │ │ ├── PerformanceListener.java │ │ │ └── conditions │ │ │ │ ├── JooqBaseCondition.java │ │ │ │ └── JooqStringCondition.java │ │ │ └── jpa │ │ │ └── JpaConfig.java │ │ └── resources │ │ └── application.properties ├── application-dsl-by-testcontainer │ ├── .gitignore │ ├── build.gradle │ ├── jooq-codegen-ddl.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sight │ │ │ │ └── application │ │ │ │ └── tc │ │ │ │ ├── JooqTcDSLApplication.java │ │ │ │ ├── config │ │ │ │ ├── datasource │ │ │ │ │ └── DatasourceConfig.java │ │ │ │ └── jooq │ │ │ │ │ ├── ExceptionTranslator.java │ │ │ │ │ ├── JooqConfig.java │ │ │ │ │ ├── PerformanceListener.java │ │ │ │ │ └── meta │ │ │ │ │ └── conditions │ │ │ │ │ ├── JooqBaseCondition.java │ │ │ │ │ └── JooqStringCondition.java │ │ │ │ ├── dtos │ │ │ │ ├── CategorySummaryDto.java │ │ │ │ └── FilmSummaryDto.java │ │ │ │ ├── repository │ │ │ │ ├── CategoryJooqRepository.java │ │ │ │ └── FilmJooqRepository.java │ │ │ │ └── service │ │ │ │ └── FilmService.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── db │ │ │ ├── migration │ │ │ └── V1__init_tables.sql │ │ │ ├── mysql-sakila-ddl.sql │ │ │ ├── mysql-sakila-delete-data.sql │ │ │ ├── mysql-sakila-drop-objects.sql │ │ │ ├── mysql-sakila-insert-data.sql │ │ │ └── mysql-sakila-schema.sql │ │ └── test │ │ └── java │ │ └── com │ │ └── sight │ │ └── application │ │ └── tc │ │ ├── CategoryJooqRepositoryTest.java │ │ ├── FilmRepositoryTest.java │ │ └── config │ │ ├── IntegrationTest.java │ │ └── JooqRepositoryTest.java ├── build.gradle ├── docker-compose.yml ├── entity │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── sight │ │ └── entity │ │ ├── Actor.java │ │ ├── Address.java │ │ ├── Category.java │ │ ├── City.java │ │ ├── Country.java │ │ ├── Customer.java │ │ ├── Film.java │ │ ├── FilmActor.java │ │ ├── FilmCategory.java │ │ ├── FilmText.java │ │ ├── Inventory.java │ │ ├── Language.java │ │ ├── Payment.java │ │ ├── Rental.java │ │ ├── Staff.java │ │ ├── Store.java │ │ └── naming │ │ └── QuotedPhysicalNamingStrategy.java ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jooq-custom │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── jooq │ │ └── custom │ │ └── generator │ │ └── JPrefixGeneratorStrategy.java └── settings.gradle ├── jooq-start ├── .gitignore ├── README.md ├── build.gradle ├── docker-compose.yml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jooq.gradle ├── md-asset │ ├── 1-test-code.PNG │ ├── 2-returning-insert.PNG │ ├── 3-select-delete.PNG │ ├── 4-join-query.PNG │ ├── 5-dtos.PNG │ └── 6-join-dto.PNG ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sight │ │ │ └── jooqstart │ │ │ ├── JooqStartApplication.java │ │ │ ├── app │ │ │ └── domain │ │ │ │ ├── author │ │ │ │ ├── AuthorBookDto.java │ │ │ │ ├── AuthorDto.java │ │ │ │ └── AuthorRepository.java │ │ │ │ └── book │ │ │ │ ├── BookDto.java │ │ │ │ └── BookRepository.java │ │ │ └── config │ │ │ └── jooq │ │ │ └── JooqConfig.java │ └── resources │ │ ├── application-test.properties │ │ ├── application.properties │ │ └── sql │ │ ├── ddl.sql │ │ └── seed.sql │ └── test │ └── java │ └── com │ └── sight │ └── jooqstart │ ├── config │ ├── AppProfile.java │ ├── IntegrationTest.java │ ├── JooqRepoTest.java │ └── jooq │ │ └── JooqTestConfig.java │ └── domain │ ├── author │ └── AuthorRepoTest.java │ └── book │ └── BookRepoTest.java ├── jooq-with-jpa ├── .gitignore ├── Dockerfile ├── application │ ├── .gitignore │ ├── build.gradle │ ├── jooq.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sight │ │ │ │ └── application │ │ │ │ ├── JooqWithJpa.java │ │ │ │ ├── app │ │ │ │ ├── domain │ │ │ │ │ └── board │ │ │ │ │ │ ├── BoardJooqRepository.java │ │ │ │ │ │ ├── BoardJpaRepository.java │ │ │ │ │ │ ├── BoardService.java │ │ │ │ │ │ ├── type │ │ │ │ │ │ ├── BoardTypeJooqRepository.java │ │ │ │ │ │ ├── BoardTypeJpaRepository.java │ │ │ │ │ │ └── BoardTypeService.java │ │ │ │ │ │ └── user │ │ │ │ │ │ ├── UserRepository.java │ │ │ │ │ │ └── UserService.java │ │ │ │ └── util │ │ │ │ │ └── RandomUtil.java │ │ │ │ ├── config │ │ │ │ ├── datasource │ │ │ │ │ └── DatasourceConfig.java │ │ │ │ ├── jooq │ │ │ │ │ ├── BaseJooqRepository.java │ │ │ │ │ ├── ExceptionTranslator.java │ │ │ │ │ ├── JooqConfig.java │ │ │ │ │ ├── PerformanceListener.java │ │ │ │ │ └── TextSearchWildcard.java │ │ │ │ └── jpa │ │ │ │ │ └── JpaConfig.java │ │ │ │ ├── dto │ │ │ │ ├── BoardRegisterRequest.java │ │ │ │ ├── BoardTypeDto.java │ │ │ │ ├── BoardTypeRegisterRequest.java │ │ │ │ └── UserRegisterRequest.java │ │ │ │ └── web │ │ │ │ ├── BoardController.java │ │ │ │ └── BoardTypeController.java │ │ └── resources │ │ │ ├── application-test.properties │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── sight │ │ └── application │ │ ├── config │ │ ├── AppProfile.java │ │ ├── IntegrationTest.java │ │ ├── JooqRepoTest.java │ │ └── jooq │ │ │ └── JooqTestConfig.java │ │ └── domain │ │ └── DataGenerationTest.java ├── build.gradle ├── ddl.sql ├── docker-compose.yml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── http │ ├── board.http │ └── http-client.env.json ├── jooq-custom │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── jooq │ │ └── custom │ │ └── generator │ │ └── JPrefixGeneratorStrategy.java ├── jooq-entity │ ├── .gitignore │ ├── build.gradle │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── sight │ │ ├── entity │ │ ├── AppUser.java │ │ ├── Board.java │ │ ├── BoardType.java │ │ └── common │ │ │ └── HistoryRequiredEntity.java │ │ └── naming │ │ └── QuotedPhysicalNamingStrategy.java └── settings.gradle ├── jpa-separate-ro-rw ├── .gitignore ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── infra │ ├── docker-compose.yml │ ├── haproxy │ │ └── config │ │ │ └── haproxy.cfg │ └── mariadb │ │ ├── config │ │ └── my.cnf │ │ ├── node-1 │ │ └── volume │ │ │ └── .gitkeep │ │ ├── node-2 │ │ └── volume │ │ │ └── .gitkeep │ │ └── node-3 │ │ └── volume │ │ └── .gitkeep ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── sight │ │ │ ├── JpaSeparateRoRwApplication.java │ │ │ ├── app │ │ │ ├── domain │ │ │ │ ├── BaseRecordableEntity.java │ │ │ │ ├── board │ │ │ │ │ ├── Board.java │ │ │ │ │ ├── BoardRepository.java │ │ │ │ │ ├── BoardRepositoryCustom.java │ │ │ │ │ ├── BoardRepositoryImpl.java │ │ │ │ │ ├── BoardService.java │ │ │ │ │ └── comment │ │ │ │ │ │ └── Comment.java │ │ │ │ └── user │ │ │ │ │ ├── MyUser.java │ │ │ │ │ ├── MyUserRepository.java │ │ │ │ │ ├── MyUserRepositoryCustom.java │ │ │ │ │ ├── MyUserRepositoryImpl.java │ │ │ │ │ └── MyUserService.java │ │ │ └── web │ │ │ │ └── dto │ │ │ │ └── user │ │ │ │ └── MyUserCreateRequest.java │ │ │ └── config │ │ │ ├── AppProfile.java │ │ │ ├── db │ │ │ ├── BaseDataSourceConfig.java │ │ │ ├── BaseDatabaseConfig.java │ │ │ ├── ChainedTransactionConfig.java │ │ │ ├── DataSourceRole.java │ │ │ ├── DataSourceType.java │ │ │ ├── board │ │ │ │ ├── BoardDataSourceConfig.java │ │ │ │ ├── BoardDatabaseConfig.java │ │ │ │ └── BoardRouteDataSource.java │ │ │ └── user │ │ │ │ ├── UserDataSourceConfig.java │ │ │ │ ├── UserDatabaseConfig.java │ │ │ │ └── UserRouteDataSource.java │ │ │ ├── jpa │ │ │ └── JpaConfig.java │ │ │ └── queryDsl │ │ │ └── QueryDslConfig.java │ └── resources │ │ ├── application-local.properties │ │ ├── application-test.properties │ │ └── application.properties │ └── test │ └── java │ └── com │ └── sight │ ├── domain │ ├── book │ │ └── BookIntegrationTest.java │ └── user │ │ └── MyUserIntegrationTest.java │ ├── testConfig │ └── JpaTestConfig.java │ └── testType │ ├── BaseTest.java │ ├── DataJpaRepoTest.java │ └── IntegrationTest.java ├── jpa-with-recursive ├── .gitignore ├── README.md ├── build.gradle.kts ├── docker-compose.yml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── infra │ └── volumes │ │ ├── mariadb │ │ └── .gitkeep │ │ ├── mssql │ │ └── .gitkeep │ │ ├── mysql │ │ └── .gitkeep │ │ ├── oracle │ │ └── .gitkeep │ │ └── postgre │ │ └── .gitkeep ├── md-asset │ ├── 1-table.png │ ├── 2_select_output.png │ ├── 3-criteria.PNG │ ├── 4-sqlresult.png │ └── 5-executionplan.PNG ├── settings.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── com │ │ │ └── sight │ │ │ └── blog │ │ │ ├── BlogApplication.kt │ │ │ ├── app │ │ │ └── domain │ │ │ │ ├── company │ │ │ │ ├── Company.kt │ │ │ │ └── CompanyRepository.kt │ │ │ │ └── department │ │ │ │ ├── Department.kt │ │ │ │ ├── DepartmentCTE.kt │ │ │ │ └── DepartmentRepository.kt │ │ │ └── common │ │ │ └── jpa │ │ │ ├── BaseRecordableEntity.kt │ │ │ ├── JpaConfig.kt │ │ │ ├── criteria │ │ │ └── CriteriaConfig.kt │ │ │ └── queryDsl │ │ │ └── QueryDslConfig.kt │ └── resources │ │ ├── application.properties │ │ └── sql │ │ └── ddl.sql │ └── test │ └── kotlin │ └── com │ └── sight │ └── blog │ ├── config │ ├── TestEnv.kt │ ├── jpa │ │ ├── CriteriaConfig.kt │ │ └── JpaTestConfig.kt │ └── test │ │ ├── BaseTest.kt │ │ ├── DataJpaRepoTest.kt │ │ ├── IntegrationTest.kt │ │ └── IntegrationTestWithNoRollback.kt │ └── domain │ ├── company │ └── CompanyDataGeneration.kt │ └── department │ ├── DepartmentDataGeneration.kt │ └── DepartmentRepoTest.kt ├── prometheus-mairadb-and-redis ├── .gitignore ├── README.md ├── galera-cluster │ ├── docker-compose.yml │ └── infra │ │ ├── mariadb │ │ ├── config │ │ │ └── my.cnf │ │ ├── master-1 │ │ │ └── volume │ │ │ │ └── .gitkeep │ │ ├── master-2 │ │ │ └── volume │ │ │ │ └── .gitkeep │ │ ├── master-3 │ │ │ └── volume │ │ │ │ └── .gitkeep │ │ └── sql │ │ │ ├── ddl.sql │ │ │ ├── seed.sql │ │ │ └── wsrep_status.sql │ │ └── prometheus │ │ ├── config │ │ └── prometheus.yml │ │ └── volume │ │ └── .gitkeep ├── redis-cluster-fail │ ├── docker-compose.yml │ ├── redis-image │ │ ├── Dockerfile │ │ ├── docker-entrypoint.sh │ │ └── redis.conf │ ├── redis-master │ │ └── data │ │ │ └── .gitkeep │ ├── redis-slave-1 │ │ └── data │ │ │ └── .gitkeep │ └── redis-slave-2 │ │ └── data │ │ └── .gitkeep └── single-node-mariadb │ ├── docker-compose.yml │ └── infra │ ├── mariadb │ └── sql │ │ ├── ddl.sql │ │ └── seed.sql │ └── prometheus │ └── prometheus.yml └── reactor-java ├── .DS_Store ├── .gitignore ├── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src └── test └── java ├── BackPressureTest.java ├── BackpressureBufferStrategyTest.java └── BackpressureErrorStrategyTest.java /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dong Min Seol 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 블로그 포스팅용 코드 레포 2 | 3 | https://sightstudio.tistory.com 에서 작성한 포스팅에 사용된 코드들을 모아놓은 레포입니다. 4 | -------------------------------------------------------------------------------- /archunit-start/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /archunit-start/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.5' 4 | id 'io.spring.dependency-management' version '1.1.6' 5 | } 6 | 7 | group = 'com.sight' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(21) 13 | } 14 | } 15 | 16 | repositories { 17 | mavenCentral() 18 | } 19 | 20 | dependencies { 21 | 22 | implementation 'org.springframework.boot:spring-boot-starter' 23 | implementation 'org.springframework.boot:spring-boot-starter-web' 24 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 25 | 26 | compileOnly 'org.projectlombok:lombok' 27 | annotationProcessor 'org.projectlombok:lombok' 28 | runtimeOnly 'com.mysql:mysql-connector-j' 29 | 30 | testImplementation 'com.tngtech.archunit:archunit:1.3.0' 31 | testImplementation 'com.tngtech.archunit:archunit-junit5:1.3.0' 32 | 33 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 34 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 35 | } 36 | 37 | tasks.named('test') { 38 | useJUnitPlatform() 39 | } 40 | -------------------------------------------------------------------------------- /archunit-start/docs/InfrastructureLayer.puml: -------------------------------------------------------------------------------- 1 | @startuml 2 | 3 | class ActorService<> { 4 | - ActorInfraManager actorInfraManager 5 | 6 | + doSomethingWithDomain() 7 | } 8 | 9 | class ActorInfraManager<> { 10 | - ActorRepository actorRepository 11 | - ActorDao actorNativeDao 12 | } 13 | 14 | class ActorRepository<> { 15 | 16 | } 17 | 18 | class ActorDao<> { 19 | 20 | } 21 | 22 | class ActorConsumer<> { 23 | 24 | } 25 | 26 | class ActorPublisher<> { 27 | 28 | } 29 | 30 | 31 | ActorInfraManager *-- ActorRepository : "has a" 32 | ActorInfraManager *-- ActorDao : "has a" 33 | ActorInfraManager *-- ActorConsumer : "has a" 34 | ActorInfraManager *-- ActorPublisher : "has a" 35 | 36 | ActorService *-- ActorInfraManager : "has a" 37 | 38 | @enduml 39 | -------------------------------------------------------------------------------- /archunit-start/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/archunit-start/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /archunit-start/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /archunit-start/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'archunit-start' 2 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/ArchunitStartApplication.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ArchunitStartApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ArchunitStartApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/controller/CamelUrlController.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.controller; 2 | 3 | import com.sight.archunitstart.dto.Actor; 4 | import com.sight.archunitstart.dto.ActorExtension; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | @RestController 10 | @RequiredArgsConstructor 11 | public class CamelUrlController { 12 | 13 | /** 14 | * 상속된 형태를 가진 DTO를 리턴하는 케이스 15 | * ArchUnit에서 해당 케이스를 파악하고, 테스트에서 Fail 시켜야한다. 16 | */ 17 | @GetMapping("/thisIsCamelUrl") 18 | public Actor camelUrl() { 19 | return new Actor(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/controller/InheritanceDtoController.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.controller; 2 | 3 | import com.sight.archunitstart.dto.ActorExtension; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @RequiredArgsConstructor 10 | public class InheritanceDtoController { 11 | 12 | /** 13 | * 상속된 형태를 가진 DTO를 리턴하는 케이스 14 | * ArchUnit에서 해당 케이스를 파악하고, 테스트에서 Fail 시켜야한다. 15 | */ 16 | @GetMapping("/get-some-data") 17 | public ActorExtension returnInheritDto() { 18 | return new ActorExtension(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/domain/actor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/archunit-start/src/main/java/com/sight/archunitstart/domain/actor/.gitkeep -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/domain/actor/model/ActorEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.domain.actor.model; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import org.hibernate.annotations.ColumnDefault; 7 | 8 | import java.time.Instant; 9 | 10 | @Getter 11 | @Setter 12 | @Entity 13 | @Table(name = "actor") 14 | public class ActorEntity { 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | @Column(name = "actor_id", columnDefinition = "int UNSIGNED not null") 18 | private Long id; 19 | 20 | @Transient 21 | @Column(name = "first_name", nullable = false, length = 45) 22 | private String firstName; 23 | 24 | @Column(name = "last_name", nullable = false, length = 45) 25 | private String lastName; 26 | 27 | @ColumnDefault("CURRENT_TIMESTAMP") 28 | @Column(name = "last_update", nullable = false) 29 | private Instant lastUpdate; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/domain/actor/model/ActorRepository.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.domain.actor.model; 2 | 3 | import com.sight.archunitstart.dto.Actor; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface ActorRepository extends JpaRepository { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/domain/film/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/archunit-start/src/main/java/com/sight/archunitstart/domain/film/.gitkeep -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/domain/film/model/FilmActorEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.domain.film.model; 2 | 3 | import com.sight.archunitstart.domain.actor.model.ActorEntity; 4 | import com.sight.archunitstart.enitty.FilmEntity; 5 | import jakarta.persistence.*; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | import org.hibernate.annotations.ColumnDefault; 9 | 10 | import java.time.Instant; 11 | 12 | @Getter 13 | @Setter 14 | @Entity 15 | @Table(name = "film_actor") 16 | public class FilmActorEntity { 17 | @EmbeddedId 18 | private FilmActorId id; 19 | 20 | @MapsId("actorId") 21 | @ManyToOne(fetch = FetchType.LAZY, optional = false) 22 | @JoinColumn(name = "actor_id", nullable = false) 23 | private ActorEntity actor; 24 | 25 | @MapsId("filmId") 26 | @ManyToOne(fetch = FetchType.LAZY, optional = false) 27 | @JoinColumn(name = "film_id", nullable = false) 28 | private FilmEntity film; 29 | 30 | @ColumnDefault("CURRENT_TIMESTAMP") 31 | @Column(name = "last_update", nullable = false) 32 | private Instant lastUpdate; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/dto/Actor.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.dto; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class Actor { 7 | private String name; 8 | private int age; 9 | } 10 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/dto/ActorExtension.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Setter 7 | @Getter 8 | public class ActorExtension extends Actor { 9 | 10 | private String extension; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/enitty/CategoryEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.enitty; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import org.hibernate.annotations.ColumnDefault; 10 | 11 | import java.time.Instant; 12 | 13 | @Getter 14 | @Setter 15 | @Entity 16 | @Table(name = "category") 17 | public class CategoryEntity { 18 | @Id 19 | @Column(name = "category_id", columnDefinition = "int UNSIGNED not null") 20 | private Long id; 21 | 22 | @Column(name = "name", nullable = false, length = 25) 23 | private String name; 24 | 25 | @ColumnDefault("CURRENT_TIMESTAMP") 26 | @Column(name = "last_update", nullable = false) 27 | private Instant lastUpdate; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/enitty/CityEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.enitty; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import org.hibernate.annotations.ColumnDefault; 7 | 8 | import java.time.Instant; 9 | 10 | @Getter 11 | @Setter 12 | @Entity 13 | @Table(name = "city") 14 | public class CityEntity { 15 | @Id 16 | @Column(name = "city_id", columnDefinition = "int UNSIGNED not null") 17 | private Long id; 18 | 19 | @Column(name = "city", nullable = false, length = 50) 20 | private String city; 21 | 22 | @ManyToOne(fetch = FetchType.LAZY, optional = false) 23 | @JoinColumn(name = "country_id", nullable = false) 24 | private CountryEntity country; 25 | 26 | @ColumnDefault("CURRENT_TIMESTAMP") 27 | @Column(name = "last_update", nullable = false) 28 | private Instant lastUpdate; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/enitty/CountryEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.enitty; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import org.hibernate.annotations.ColumnDefault; 10 | 11 | import java.time.Instant; 12 | 13 | @Getter 14 | @Setter 15 | @Entity 16 | @Table(name = "country") 17 | public class CountryEntity { 18 | @Id 19 | @Column(name = "country_id", columnDefinition = "int UNSIGNED not null") 20 | private Long id; 21 | 22 | @Column(name = "country", nullable = false, length = 50) 23 | private String country; 24 | 25 | @ColumnDefault("CURRENT_TIMESTAMP") 26 | @Column(name = "last_update", nullable = false) 27 | private Instant lastUpdate; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/enitty/FilmCategoryEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.enitty; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import org.hibernate.annotations.ColumnDefault; 7 | 8 | import java.time.Instant; 9 | 10 | @Getter 11 | @Setter 12 | @Entity 13 | @Table(name = "film_category") 14 | public class FilmCategoryEntity { 15 | @EmbeddedId 16 | private FilmCategoryId id; 17 | 18 | @MapsId("filmId") 19 | @ManyToOne(fetch = FetchType.LAZY, optional = false) 20 | @JoinColumn(name = "film_id", nullable = false) 21 | private FilmEntity film; 22 | 23 | @MapsId("categoryId") 24 | @ManyToOne(fetch = FetchType.LAZY, optional = false) 25 | @JoinColumn(name = "category_id", nullable = false) 26 | private CategoryEntity category; 27 | 28 | @ColumnDefault("CURRENT_TIMESTAMP") 29 | @Column(name = "last_update", nullable = false) 30 | private Instant lastUpdate; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/enitty/FilmTextEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.enitty; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | @Entity 10 | @Table(name = "film_text") 11 | public class FilmTextEntity { 12 | 13 | @Id 14 | @Column(name = "film_id", nullable = false) 15 | private Integer id; 16 | 17 | @Column(name = "title", nullable = false) 18 | private String title; 19 | 20 | @Lob 21 | @Column(name = "description") 22 | private String description; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/enitty/InventoryEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.enitty; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import org.hibernate.annotations.ColumnDefault; 7 | 8 | import java.time.Instant; 9 | 10 | @Getter 11 | @Setter 12 | @Entity 13 | @Table(name = "inventory") 14 | public class InventoryEntity { 15 | @Id 16 | @Column(name = "inventory_id", columnDefinition = "int UNSIGNED not null") 17 | private Long id; 18 | 19 | @ManyToOne(fetch = FetchType.LAZY, optional = false) 20 | @JoinColumn(name = "film_id", nullable = false) 21 | private FilmEntity film; 22 | 23 | @ManyToOne(fetch = FetchType.LAZY, optional = false) 24 | @JoinColumn(name = "store_id", nullable = false) 25 | private StoreEntity store; 26 | 27 | @ColumnDefault("CURRENT_TIMESTAMP") 28 | @Column(name = "last_update", nullable = false) 29 | private Instant lastUpdate; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/enitty/LanguageEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.enitty; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | import org.hibernate.annotations.ColumnDefault; 10 | 11 | import java.time.Instant; 12 | 13 | @Getter 14 | @Setter 15 | @Entity 16 | @Table(name = "language") 17 | public class LanguageEntity { 18 | @Id 19 | @Column(name = "language_id", columnDefinition = "int UNSIGNED not null") 20 | private Long id; 21 | 22 | @Column(name = "name", nullable = false, length = 20) 23 | private String name; 24 | 25 | @ColumnDefault("CURRENT_TIMESTAMP") 26 | @Column(name = "last_update", nullable = false) 27 | private Instant lastUpdate; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/enitty/StoreEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.enitty; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | import org.hibernate.annotations.ColumnDefault; 7 | 8 | import java.time.Instant; 9 | 10 | @Getter 11 | @Setter 12 | @Entity 13 | @Table(name = "store") 14 | public class StoreEntity { 15 | @Id 16 | @Column(name = "store_id", columnDefinition = "int UNSIGNED not null") 17 | private Long id; 18 | 19 | @OneToOne(fetch = FetchType.LAZY, optional = false) 20 | @JoinColumn(name = "manager_staff_id", nullable = false) 21 | private StaffEntity managerStaff; 22 | 23 | @ManyToOne(fetch = FetchType.LAZY, optional = false) 24 | @JoinColumn(name = "address_id", nullable = false) 25 | private AddressEntity address; 26 | 27 | @ColumnDefault("CURRENT_TIMESTAMP") 28 | @Column(name = "last_update", nullable = false) 29 | private Instant lastUpdate; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /archunit-start/src/main/java/com/sight/archunitstart/service/ActorService.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.service; 2 | 3 | import com.sight.archunitstart.domain.actor.model.ActorRepository; 4 | import com.sight.archunitstart.dto.Actor; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service 9 | @RequiredArgsConstructor 10 | public class ActorService { 11 | 12 | private final ActorRepository actorRepository; 13 | 14 | public void saveActor() { 15 | actorRepository.save(new Actor()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /archunit-start/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=archunit-start 2 | 3 | # MySQL 4 | spring.datasource.url=jdbc:mysql://localhost:3306/sakila 5 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 6 | spring.datasource.username=root 7 | spring.datasource.password=passwd 8 | 9 | #JPA 10 | #spring.jpa.show-sql=true 11 | spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect 12 | spring.jpa.properties.hibernate.format_sql=true 13 | spring.jpa.properties.hibernate.show_sql=true 14 | spring.jpa.hibernate.ddl-auto=none 15 | -------------------------------------------------------------------------------- /archunit-start/src/test/java/com/sight/archunitstart/config/ArchitectureTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.archunitstart.config; 2 | 3 | import com.tngtech.archunit.core.domain.JavaClasses; 4 | import com.tngtech.archunit.core.importer.ClassFileImporter; 5 | import com.tngtech.archunit.core.importer.ImportOption; 6 | import org.junit.jupiter.api.BeforeAll; 7 | 8 | 9 | 10 | public abstract class ArchitectureTest { 11 | 12 | protected static JavaClasses classes; 13 | 14 | @BeforeAll 15 | public static void setUp() { 16 | classes = new ClassFileImporter() 17 | .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) 18 | .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_ARCHIVES) 19 | .importPackages("com.sight.archunitstart"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dependent-subquery/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /dependent-subquery/application/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/java/com/sight/application/DependentSubqueryApplication.java: -------------------------------------------------------------------------------- 1 | package com.sight.application; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DependentSubqueryApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DependentSubqueryApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/java/com/sight/application/app/util/RandomUtil.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.util; 2 | 3 | import java.time.LocalDate; 4 | import java.time.LocalDateTime; 5 | import java.time.LocalTime; 6 | import java.util.concurrent.ThreadLocalRandom; 7 | 8 | public class RandomUtil { 9 | 10 | public static LocalDateTime getRandomDateTime(LocalDate dateStart, LocalDate dateEnd) { 11 | 12 | // [random date] 13 | long minDay = dateStart.toEpochDay(); 14 | long maxDay = dateEnd.toEpochDay(); 15 | 16 | long randomDay = ThreadLocalRandom.current().nextLong(minDay, maxDay); 17 | LocalDate randomDate = LocalDate.ofEpochDay(randomDay); 18 | 19 | // [random time] 20 | int startSeconds = LocalTime.of(0, 0).toSecondOfDay(); 21 | int endSeconds = LocalTime.of(23, 59).toSecondOfDay(); 22 | int randomTimeSecond = ThreadLocalRandom 23 | .current() 24 | .nextInt(startSeconds, endSeconds); 25 | LocalTime randomTime = LocalTime.ofSecondOfDay(randomTimeSecond); 26 | 27 | return LocalDateTime.of(randomDate, randomTime); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/java/com/sight/application/config/jooq/ExceptionTranslator.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import org.jooq.ExecuteContext; 4 | import org.jooq.SQLDialect; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; 7 | import org.springframework.jdbc.support.SQLExceptionTranslator; 8 | 9 | public class ExceptionTranslator extends DefaultExecuteListener { 10 | public void exception(ExecuteContext context) { 11 | SQLDialect dialect = context.configuration().dialect(); 12 | SQLExceptionTranslator translator = new SQLErrorCodeSQLExceptionTranslator(dialect.name()); 13 | 14 | context.exception(translator 15 | .translate("Access database using Jooq", context.sql(), context.sqlException())); 16 | } 17 | } -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/java/com/sight/application/config/jooq/PerformanceListener.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.jooq.ExecuteContext; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.jooq.tools.StopWatch; 7 | 8 | @Slf4j 9 | public class PerformanceListener extends DefaultExecuteListener { 10 | 11 | StopWatch watch; 12 | 13 | @Override 14 | public void executeStart(ExecuteContext ctx) { 15 | super.executeStart(ctx); 16 | watch = new StopWatch(); 17 | } 18 | 19 | @Override 20 | public void executeEnd(ExecuteContext ctx) { 21 | super.executeEnd(ctx); 22 | if (watch.split() > 5_000_000_000L) 23 | log.warn("Slow Query Detected: \n" + ctx.query(), new Exception()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/java/com/sight/application/config/jooq/TextSearchWildcard.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | public enum TextSearchWildcard { 4 | PREFIX, SUFFIX, FULL_TEXT, NONE 5 | } 6 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/java/com/sight/application/web/BoardRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.web; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class BoardRegisterRequest { 11 | private String title; 12 | private String content; 13 | private Long boardTypeSeq; 14 | private Long userSeq; 15 | } 16 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/java/com/sight/application/web/BoardTypeRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.web; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class BoardTypeRegisterRequest { 11 | private String code; 12 | private String codeName; 13 | } 14 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/java/com/sight/application/web/UserRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.web; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class UserRegisterRequest { 11 | private String userId; 12 | private String userName; 13 | } 14 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.url=jdbc:mysql://localhost:3306/jooq 3 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 4 | spring.datasource.username=root 5 | spring.datasource.password=passwd 6 | spring.jooq.sql-dialect=MySQL 7 | spring.jpa.properties.hibernate.format_sql= true 8 | spring.jpa.properties.hibernate.use_sql_comments= true 9 | logging.level.org.jooq.tools.LoggerListener=DEBUG -------------------------------------------------------------------------------- /dependent-subquery/application/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.url=jdbc:mysql://localhost:3306/jooq 3 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 4 | spring.datasource.username=root 5 | spring.datasource.password=passwd 6 | spring.jpa.properties.hibernate.format_sql= true 7 | spring.jpa.properties.hibernate.use_sql_comments= true 8 | logging.level.org.jooq.tools.LoggerListener=DEBUG -------------------------------------------------------------------------------- /dependent-subquery/application/src/test/java/com/sight/application/config/AppProfile.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config; 2 | 3 | public interface AppProfile { 4 | String PROD = "prod"; 5 | String TEST = "test"; 6 | } 7 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/test/java/com/sight/application/config/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config; 2 | 3 | import org.springframework.boot.test.context.SpringBootTest; 4 | import org.springframework.context.annotation.Profile; 5 | 6 | @Profile(AppProfile.TEST) 7 | @SpringBootTest 8 | public abstract class IntegrationTest { } 9 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/test/java/com/sight/application/config/JooqRepoTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config; 2 | 3 | import com.sight.application.config.jooq.JooqTestConfig; 4 | import org.springframework.boot.test.autoconfigure.jooq.JooqTest; 5 | import org.springframework.context.annotation.Import; 6 | import org.springframework.context.annotation.Profile; 7 | 8 | @Import(JooqTestConfig.class) 9 | @Profile(AppProfile.TEST) 10 | @JooqTest 11 | public abstract class JooqRepoTest { } 12 | -------------------------------------------------------------------------------- /dependent-subquery/application/src/test/java/com/sight/application/config/jooq/JooqTestConfig.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import org.modelmapper.ModelMapper; 4 | import org.modelmapper.convention.NameTokenizers; 5 | import org.modelmapper.jooq.RecordValueReader; 6 | import org.modelmapper.module.jdk8.Jdk8Module; 7 | import org.modelmapper.module.jsr310.Jsr310Module; 8 | import org.springframework.boot.test.context.TestConfiguration; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | @TestConfiguration 12 | public class JooqTestConfig { 13 | 14 | @Bean 15 | public ModelMapper modelMapper() { 16 | ModelMapper mapper = new ModelMapper(); 17 | mapper.registerModule(new Jsr310Module()); 18 | mapper.registerModule(new Jdk8Module()); 19 | 20 | mapper.getConfiguration() 21 | .setSourceNameTokenizer(NameTokenizers.UNDERSCORE) 22 | .addValueReader(new RecordValueReader()); 23 | 24 | return mapper; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /dependent-subquery/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | jooq-db-mysql: 4 | image: mysql:8.0.27 5 | volumes: 6 | - test_volume:/data 7 | ports: 8 | - '3306:3306' 9 | environment: 10 | MYSQL_ROOT_PASSWORD: passwd 11 | MYSQL_DATABASE: jooq 12 | command: 13 | ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] 14 | 15 | volumes: 16 | test_volume: -------------------------------------------------------------------------------- /dependent-subquery/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/dependent-subquery/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /dependent-subquery/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /dependent-subquery/jooq-custom/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /dependent-subquery/jooq-custom/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { id 'nu.studer.jooq' } 2 | bootJar { enabled = false } 3 | jar { enabled = true } 4 | 5 | dependencies { 6 | implementation project(':jooq-entity') 7 | implementation "org.jooq:jooq-codegen:${jooqVersion}" 8 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 9 | } -------------------------------------------------------------------------------- /dependent-subquery/jooq-custom/src/main/java/jooq/custom/generator/JPrefixGeneratorStrategy.java: -------------------------------------------------------------------------------- 1 | package jooq.custom.generator; 2 | import org.jooq.codegen.DefaultGeneratorStrategy; 3 | import org.jooq.meta.Definition; 4 | 5 | public class JPrefixGeneratorStrategy extends DefaultGeneratorStrategy { 6 | 7 | @Override 8 | public String getJavaClassName(final Definition definition, final Mode mode) { 9 | if (mode == Mode.RECORD || mode == Mode.POJO || mode == Mode.DEFAULT) { 10 | return "J" + super.getJavaClassName(definition, mode); 11 | } 12 | return super.getJavaClassName(definition, mode); 13 | } 14 | 15 | 16 | } -------------------------------------------------------------------------------- /dependent-subquery/jooq-entity/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /dependent-subquery/jooq-entity/build.gradle: -------------------------------------------------------------------------------- 1 | bootJar { enabled = false } 2 | jar { enabled = true } 3 | 4 | dependencies { 5 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 6 | implementation 'org.hibernate:hibernate-core-jakarta:5.6.7.Final' 7 | implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.0' 8 | implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0' 9 | compileOnly 'org.projectlombok:lombok' 10 | annotationProcessor 'org.projectlombok:lombok' 11 | testCompileOnly 'org.projectlombok:lombok' 12 | testAnnotationProcessor 'org.projectlombok:lombok' 13 | } -------------------------------------------------------------------------------- /dependent-subquery/jooq-entity/src/main/java/com/sight/entity/AppUser.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @Getter 9 | @Setter 10 | @Entity 11 | @Table(name = "app_user") 12 | @NoArgsConstructor 13 | public class AppUser { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | @Column(name = "user_seq", nullable = false) 18 | private Long userSeq; 19 | 20 | @Column(name = "user_id", nullable = false, unique = true) 21 | private String userId; 22 | 23 | @Column(name = "user_name", nullable = false) 24 | private String userName; 25 | } 26 | -------------------------------------------------------------------------------- /dependent-subquery/jooq-entity/src/main/java/com/sight/entity/Board.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity; 2 | 3 | import com.sight.entity.common.HistoryRequiredEntity; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import jakarta.persistence.*; 8 | 9 | @Getter 10 | @Setter 11 | @Entity 12 | @Table(name = "board") 13 | @NoArgsConstructor 14 | public class Board extends HistoryRequiredEntity { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | @Column(name = "board_seq", nullable = false) 19 | private Long boardSeq; 20 | 21 | @Column(name = "title", nullable = false) 22 | private String title; 23 | 24 | @Column(name = "content", nullable = false) 25 | private String content; 26 | 27 | @ManyToOne(fetch = FetchType.LAZY) 28 | @JoinColumn(name = "board_type_seq", nullable = false) 29 | private BoardType boardType; 30 | 31 | @ManyToOne(fetch = FetchType.LAZY) 32 | @JoinColumn(name = "user_seq", nullable = false) 33 | private AppUser writer; 34 | } 35 | -------------------------------------------------------------------------------- /dependent-subquery/jooq-entity/src/main/java/com/sight/entity/BoardType.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | 9 | @Getter 10 | @Setter 11 | @Entity 12 | @Table(name = "board_type") 13 | @NoArgsConstructor 14 | public class BoardType { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | @Column(name = "board_type_seq", nullable = false) 19 | private Long boardTypeSeq; 20 | 21 | @Column(name = "code", nullable = false) 22 | private String code; 23 | 24 | @Column(name = "code_name", nullable = false) 25 | private String codeName; 26 | } 27 | -------------------------------------------------------------------------------- /dependent-subquery/jooq-entity/src/main/java/com/sight/entity/common/HistoryRequiredEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity.common; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.EntityListeners; 5 | import jakarta.persistence.MappedSuperclass; 6 | import org.springframework.data.annotation.CreatedDate; 7 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 8 | 9 | import java.time.LocalDateTime; 10 | 11 | @EntityListeners(AuditingEntityListener.class) 12 | @MappedSuperclass 13 | public class HistoryRequiredEntity { 14 | 15 | @CreatedDate 16 | @Column(name = "reg_date") 17 | LocalDateTime regDate; 18 | } 19 | -------------------------------------------------------------------------------- /dependent-subquery/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jooq-dependent-subquery' 2 | include 'jooq-custom' 3 | include 'jooq-entity' 4 | include 'application' -------------------------------------------------------------------------------- /galera-cluster-mariadb/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### IntelliJ IDEA ### 9 | .idea 10 | *.iws 11 | *.iml 12 | *.ipr 13 | out/ 14 | !**/src/main/**/out/ 15 | !**/src/test/**/out/ 16 | 17 | ## galera cluster - mariadb node volumes 18 | infra/mariadb/master-1/volume 19 | !infra/mariadb/master-1/volume/.gitkeep 20 | 21 | infra/mariadb/master-2/volume 22 | !infra/mariadb/master-2/volume/.gitkeep 23 | 24 | infra/mariadb/master-3/volume 25 | !infra/mariadb/master-3/volume/.gitkeep 26 | 27 | -------------------------------------------------------------------------------- /galera-cluster-mariadb/doc_img/GALERA_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/doc_img/GALERA_1.PNG -------------------------------------------------------------------------------- /galera-cluster-mariadb/doc_img/SELF_LEAVE.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/doc_img/SELF_LEAVE.PNG -------------------------------------------------------------------------------- /galera-cluster-mariadb/doc_img/first-comitters-win.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/doc_img/first-comitters-win.png -------------------------------------------------------------------------------- /galera-cluster-mariadb/doc_img/first-comitters-win_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/doc_img/first-comitters-win_2.png -------------------------------------------------------------------------------- /galera-cluster-mariadb/doc_img/ist.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/doc_img/ist.PNG -------------------------------------------------------------------------------- /galera-cluster-mariadb/doc_img/마스터_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/doc_img/마스터_1.PNG -------------------------------------------------------------------------------- /galera-cluster-mariadb/doc_img/마스터_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/doc_img/마스터_2.PNG -------------------------------------------------------------------------------- /galera-cluster-mariadb/doc_img/마스터_3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/doc_img/마스터_3.PNG -------------------------------------------------------------------------------- /galera-cluster-mariadb/infra/mariadb/config/my.cnf: -------------------------------------------------------------------------------- 1 | [galera] 2 | # Mandatory settings 3 | wsrep_on=ON 4 | wsrep_provider=/usr/lib/galera/libgalera_smm.so 5 | wsrep_cluster_address=gcomm://galera-master-node-1,galera-master-node-2,galera-master-node-3 6 | binlog_format=row 7 | default_storage_engine=InnoDB 8 | innodb_autoinc_lock_mode=2 9 | 10 | [mysqld] 11 | character-set-server = utf8 12 | collation-server = utf8_unicode_ci 13 | skip-character-set-client-handshake 14 | innodb_print_all_deadlocks = 1 15 | 16 | # GCache size zero for SST test | default = 128M 17 | 18 | wsrep_provider_options="gcache.size=0;gcache.page_size=0" 19 | # wsrep_provider_options="gcache.size=128M;gcache.page_size=128M" -------------------------------------------------------------------------------- /galera-cluster-mariadb/infra/mariadb/master-4/volume/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/infra/mariadb/master-4/volume/.gitkeep -------------------------------------------------------------------------------- /galera-cluster-mariadb/infra/mariadb/master-5/volume/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/galera-cluster-mariadb/infra/mariadb/master-5/volume/.gitkeep -------------------------------------------------------------------------------- /galera-cluster-mariadb/infra/mariadb/sql/ddl.sql: -------------------------------------------------------------------------------- 1 | create table author 2 | ( 3 | id int(7) not null primary key AUTO_INCREMENT, 4 | first_name varchar(50) null, 5 | last_name varchar(50) not null, 6 | date_of_birth date null, 7 | year_of_birth int(7) null, 8 | distinguished int(1) null 9 | ); 10 | 11 | create table book_store 12 | ( 13 | name varchar(400) not null, 14 | constraint name unique (name) 15 | ); 16 | 17 | create table language 18 | ( 19 | id int(7) not null primary key AUTO_INCREMENT, 20 | cd char(2) not null, 21 | description varchar(50) null 22 | ); 23 | 24 | create table book 25 | ( 26 | id int(7) not null primary key AUTO_INCREMENT, 27 | author_id int(7) not null, 28 | title varchar(400) not null, 29 | published_in int(7) not null, 30 | language_id int(7) not null, 31 | ); 32 | 33 | create table book_to_book_store 34 | ( 35 | name varchar(400) not null, 36 | book_id int not null, 37 | stock int null, 38 | primary key (name, book_id), 39 | ); -------------------------------------------------------------------------------- /galera-cluster-mariadb/infra/mariadb/sql/seed.sql: -------------------------------------------------------------------------------- 1 | insert into author (first_name, last_name, date_of_birth, year_of_birth, distinguished) 2 | values ('George', 'Orwell', '1903-06-26', 1903, null), 3 | ('Paulo', 'Coelho', '1947-08-24', 1947, null); 4 | 5 | insert into language (cd, description) 6 | values ('en', 'English'), 7 | ('de', 'Deutsch'), 8 | ('fr', 'Français'), 9 | ('pt', 'Português'); 10 | 11 | insert into book (author_id, title, published_in, language_id) 12 | values (1, '1984', 1948, 1), 13 | (1, 'Animal Farm', 1945, 1), 14 | (2, 'O Alquimista', 1988, 4), 15 | (2, 'Brida', 1990, 2); 16 | 17 | 18 | insert into book_store (name) 19 | values ('Buchhandlung im Volkshaus'), 20 | ('Ex Libris'), 21 | ('Orell Füssli'); 22 | 23 | insert into book_to_book_store (name, book_id, stock) 24 | values ('Buchhandlung im Volkshaus', 3, 1), 25 | ('Ex Libris', 1, 1), 26 | ('Ex Libris', 3, 2), 27 | ('Orell Füssli', 1, 10), 28 | ('Orell Füssli', 2, 10), 29 | ('Orell Füssli', 3, 10); -------------------------------------------------------------------------------- /galera-cluster-mariadb/infra/mariadb/sql/wsrep_status.sql: -------------------------------------------------------------------------------- 1 | show status like 'wsrep%'; 2 | show global status like 'wsrep_cluster_size'; 3 | show global status like 'wsrep_cluster_status'; -------------------------------------------------------------------------------- /jooq-advanced/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /jooq-advanced/README.md: -------------------------------------------------------------------------------- 1 | ### 2 | 3 | init SQL 파일 : ```/infra/mysql/init``` -------------------------------------------------------------------------------- /jooq-advanced/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | jooq-db-mysql: 4 | image: mysql:8.0.27 5 | volumes: 6 | - ./infra/mysql/volumes:/data 7 | ports: 8 | - '3306:3306' 9 | environment: 10 | MYSQL_ROOT_PASSWORD: passwd 11 | MYSQL_DATABASE: jooq 12 | command: 13 | ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] -------------------------------------------------------------------------------- /jooq-advanced/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-advanced/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /jooq-advanced/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /jooq-advanced/infra/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-advanced/infra/.gitkeep -------------------------------------------------------------------------------- /jooq-advanced/infra/mysql/init/ddl.sql: -------------------------------------------------------------------------------- 1 | create table author 2 | ( 3 | id int(7) not null primary key AUTO_INCREMENT, 4 | first_name varchar(50) null, 5 | last_name varchar(50) not null, 6 | date_of_birth date null, 7 | year_of_birth int(7) null, 8 | distinguished int(1) null 9 | ); 10 | 11 | create table book_store 12 | ( 13 | name varchar(400) not null, 14 | constraint name unique (name) 15 | ); 16 | 17 | create table language 18 | ( 19 | id int(7) not null primary key AUTO_INCREMENT, 20 | cd char(2) not null, 21 | description varchar(50) null 22 | ); 23 | 24 | create table book 25 | ( 26 | id int(7) not null primary key AUTO_INCREMENT, 27 | author_id int(7) not null, 28 | title varchar(400) not null, 29 | published_in int(7) not null, 30 | language_id int(7) not null 31 | ); 32 | 33 | create table book_to_book_store 34 | ( 35 | name varchar(400) not null, 36 | book_id int not null, 37 | stock int null, 38 | primary key (name, book_id) 39 | ); -------------------------------------------------------------------------------- /jooq-advanced/infra/mysql/init/seed.sql: -------------------------------------------------------------------------------- 1 | insert into jooq.author (first_name, last_name, date_of_birth, year_of_birth, distinguished) 2 | values ('George', 'Orwell', '1903-06-26', 1903, null), 3 | ('Paulo', 'Coelho', '1947-08-24', 1947, null); 4 | 5 | insert into jooq.language (cd, description) 6 | values ('en', 'English'), 7 | ('de', 'Deutsch'), 8 | ('fr', 'Français'), 9 | ('pt', 'Português'); 10 | 11 | insert into jooq.book (author_id, title, published_in, language_id) 12 | values (1, '1984', 1948, 1), 13 | (1, 'Animal Farm', 1945, 1), 14 | (2, 'O Alquimista', 1988, 4), 15 | (2, 'Brida', 1990, 2); 16 | 17 | 18 | insert into jooq.book_store (name) 19 | values ('Buchhandlung im Volkshaus'), 20 | ('Ex Libris'), 21 | ('Orell Füssli'); 22 | 23 | insert into jooq.book_to_book_store (name, book_id, stock) 24 | values ('Buchhandlung im Volkshaus', 3, 1), 25 | ('Ex Libris', 1, 1), 26 | ('Ex Libris', 3, 2), 27 | ('Orell Füssli', 1, 10), 28 | ('Orell Füssli', 2, 10), 29 | ('Orell Füssli', 3, 10); -------------------------------------------------------------------------------- /jooq-advanced/infra/mysql/volumes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-advanced/infra/mysql/volumes/.gitkeep -------------------------------------------------------------------------------- /jooq-advanced/jooq-custom/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | group 'com.sightstudio' 6 | version '0.0.1-SNAPSHOT' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | ext { 13 | jooqVersion = '3.15.5' 14 | } 15 | 16 | dependencies { 17 | implementation "org.jooq:jooq-codegen:${jooqVersion}" 18 | runtimeOnly 'mysql:mysql-connector-java:8.0.27' 19 | } -------------------------------------------------------------------------------- /jooq-advanced/jooq-custom/src/main/java/jooq/custom/generator/JPrefixGeneratorStrategy.java: -------------------------------------------------------------------------------- 1 | package jooq.custom.generator; 2 | import org.jooq.codegen.DefaultGeneratorStrategy; 3 | import org.jooq.meta.Definition; 4 | 5 | public class JPrefixGeneratorStrategy extends DefaultGeneratorStrategy { 6 | 7 | @Override 8 | public String getJavaClassName(final Definition definition, final Mode mode) { 9 | if (mode == Mode.RECORD || mode == Mode.POJO || mode == Mode.DEFAULT) { 10 | return "J" + super.getJavaClassName(definition, mode); 11 | } 12 | return super.getJavaClassName(definition, mode); 13 | } 14 | } -------------------------------------------------------------------------------- /jooq-advanced/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jooq-advanced' 2 | include 'jooq-custom' 3 | 4 | -------------------------------------------------------------------------------- /jooq-advanced/src/http/author.http: -------------------------------------------------------------------------------- 1 | ### 저자 등록 2 | POST {{serverURI}}/author 3 | Content-Type: application/json 4 | Accept: application/json 5 | 6 | { 7 | "firstName": "bruce", 8 | "lastName": "lee", 9 | "dateOfBirth": "2021-12-12", 10 | "yearOfBirth": "2021" 11 | } 12 | 13 | 14 | ### 저자 다중 등록 15 | POST {{serverURI}}/author/bulk 16 | Content-Type: application/json 17 | Accept: application/json 18 | 19 | { 20 | "authorList" : [ 21 | { 22 | "firstName": "bruce", 23 | "lastName": "lee", 24 | "dateOfBirth": "2021-12-12", 25 | "yearOfBirth": "2021" 26 | }, 27 | 28 | { 29 | "firstName": "roro", 30 | "lastName": "po", 31 | "dateOfBirth": "2021-12-12", 32 | "yearOfBirth": "2021" 33 | } 34 | ] 35 | } 36 | 37 | ### 저자 목록 조회 38 | GET {{serverURI}}/author 39 | Content-Type: application/json 40 | Accept: application/json -------------------------------------------------------------------------------- /jooq-advanced/src/http/http-client.env.json: -------------------------------------------------------------------------------- 1 | { 2 | "local": { 3 | "serverURI": "http://localhost:8080" 4 | } 5 | } -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/JooqAdvancedApplication.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JooqAdvancedApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JooqAdvancedApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/app/domain/author/AuthorBookDto.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.app.domain.author; 2 | 3 | import com.sightstudio.jooq.app.domain.book.BookDto; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | public class AuthorBookDto { 10 | private BookDto book; 11 | private Author author; 12 | } 13 | -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/app/domain/author/AuthorDto.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.app.domain.author; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.time.LocalDate; 7 | 8 | @Getter 9 | @Setter 10 | public class AuthorDto { 11 | 12 | private Integer id; 13 | private String firstName; 14 | private String lastName; 15 | private LocalDate dateOfBirth; 16 | private Integer yearOfBirth; 17 | 18 | public AuthorDto() { } 19 | 20 | public AuthorDto(Author author) { 21 | this.firstName = author.getFirstName(); 22 | this.lastName = author.getLastName(); 23 | this.dateOfBirth = author.getDateOfBirth(); 24 | this.yearOfBirth = author.getYearOfBirth(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/app/domain/book/BookDto.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.app.domain.book; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | 11 | @Getter 12 | @Setter 13 | @Entity 14 | public class BookDto { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | private Integer id; 19 | private Integer authorId; 20 | private String title; 21 | private Integer publishedIn; 22 | private Integer languageId; 23 | } -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/app/domain/book/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.app.domain.book; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.jooq.DSLContext; 5 | import org.modelmapper.ModelMapper; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | @RequiredArgsConstructor 10 | public class BookRepository { 11 | private final DSLContext dsl; 12 | private final ModelMapper mapper; 13 | } -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/app/web/request/AuthorBulkRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.app.web.request; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | 6 | import java.time.LocalDate; 7 | import java.util.List; 8 | 9 | @Getter 10 | @NoArgsConstructor 11 | public class AuthorBulkRegisterRequest { 12 | private List authorList; 13 | } 14 | -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/app/web/request/AuthorRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.app.web.request; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | 6 | import java.time.LocalDate; 7 | 8 | @Getter 9 | @NoArgsConstructor 10 | public class AuthorRegisterRequest { 11 | private String firstName; 12 | private String lastName; 13 | 14 | private LocalDate dateOfBirth; 15 | private Integer yearOfBirth; 16 | } 17 | -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/app/web/request/AuthorSearchRequest.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.app.web.request; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | 6 | @Getter 7 | @NoArgsConstructor 8 | public class AuthorSearchRequest { 9 | private int page = 0; 10 | private int size = 20; 11 | private String firstName = ""; 12 | private String lastName = ""; 13 | } 14 | -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/config/jooq/ExceptionTranslator.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.config.jooq; 2 | 3 | import org.jooq.ExecuteContext; 4 | import org.jooq.SQLDialect; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; 7 | import org.springframework.jdbc.support.SQLExceptionTranslator; 8 | 9 | public class ExceptionTranslator extends DefaultExecuteListener { 10 | public void exception(ExecuteContext context) { 11 | SQLDialect dialect = context.configuration().dialect(); 12 | SQLExceptionTranslator translator = new SQLErrorCodeSQLExceptionTranslator(dialect.name()); 13 | 14 | context.exception(translator 15 | .translate("Access database using Jooq", context.sql(), context.sqlException())); 16 | } 17 | } -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/config/jooq/PerformanceListener.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.config.jooq; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.jooq.ExecuteContext; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.jooq.tools.StopWatch; 7 | 8 | @Slf4j 9 | public class PerformanceListener extends DefaultExecuteListener { 10 | 11 | StopWatch watch; 12 | 13 | @Override 14 | public void executeStart(ExecuteContext ctx) { 15 | super.executeStart(ctx); 16 | watch = new StopWatch(); 17 | } 18 | 19 | @Override 20 | public void executeEnd(ExecuteContext ctx) { 21 | super.executeEnd(ctx); 22 | if (watch.split() > 5_000_000_000L) 23 | log.warn("Slow Query Detected: \n" + ctx.query(), new Exception()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jooq-advanced/src/main/java/com/sightstudio/jooq/config/jooq/TextSearchWildcard.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.config.jooq; 2 | 3 | public enum TextSearchWildcard { 4 | PREFIX, SUFFIX, FULL_TEXT, NONE 5 | } 6 | -------------------------------------------------------------------------------- /jooq-advanced/src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.url=jdbc:mysql://localhost:3306/jooq 3 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 4 | spring.datasource.username=root 5 | spring.datasource.password=passwd 6 | spring.jooq.sql-dialect=MySQL 7 | 8 | logging.level.org.jooq.tools.LoggerListener=DEBUG -------------------------------------------------------------------------------- /jooq-advanced/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.url=jdbc:mysql://localhost:3306/jooq 3 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 4 | spring.datasource.username=root 5 | spring.datasource.password=passwd 6 | 7 | logging.level.org.jooq.tools.LoggerListener=DEBUG -------------------------------------------------------------------------------- /jooq-advanced/src/test/java/com/sightstudio/jooq/JooqWithEntityApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class JooqWithEntityApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jooq-advanced/src/test/java/com/sightstudio/jooq/config/AppProfile.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.config; 2 | 3 | public interface AppProfile { 4 | String PROD = "prod"; 5 | String TEST = "test"; 6 | } 7 | -------------------------------------------------------------------------------- /jooq-advanced/src/test/java/com/sightstudio/jooq/config/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.config; 2 | 3 | import org.springframework.boot.test.context.SpringBootTest; 4 | import org.springframework.context.annotation.Profile; 5 | import org.springframework.transaction.annotation.Transactional; 6 | 7 | @Profile(AppProfile.TEST) 8 | @SpringBootTest 9 | public abstract class IntegrationTest { } 10 | -------------------------------------------------------------------------------- /jooq-advanced/src/test/java/com/sightstudio/jooq/config/JooqRepoTest.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.config; 2 | 3 | import com.sightstudio.jooq.config.jooq.JooqTestConfig; 4 | import org.springframework.boot.test.autoconfigure.jooq.JooqTest; 5 | import org.springframework.context.annotation.Import; 6 | import org.springframework.context.annotation.Profile; 7 | import org.springframework.transaction.annotation.Transactional; 8 | 9 | @Import(JooqTestConfig.class) 10 | @Profile(AppProfile.TEST) 11 | @JooqTest 12 | public abstract class JooqRepoTest { } 13 | -------------------------------------------------------------------------------- /jooq-advanced/src/test/java/com/sightstudio/jooq/config/jooq/JooqTestConfig.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.config.jooq; 2 | 3 | import org.jooq.impl.DefaultDSLContext; 4 | import org.modelmapper.ModelMapper; 5 | import org.modelmapper.convention.NameTokenizers; 6 | import org.modelmapper.jooq.RecordValueReader; 7 | import org.modelmapper.module.jdk8.Jdk8Module; 8 | import org.modelmapper.module.jsr310.Jsr310Module; 9 | import org.springframework.boot.test.context.TestConfiguration; 10 | import org.springframework.context.annotation.Bean; 11 | 12 | @TestConfiguration 13 | public class JooqTestConfig { 14 | 15 | @Bean 16 | public ModelMapper modelMapper() { 17 | ModelMapper mapper = new ModelMapper(); 18 | mapper.registerModule(new Jsr310Module()); 19 | mapper.registerModule(new Jdk8Module()); 20 | 21 | mapper.getConfiguration() 22 | .setSourceNameTokenizer(NameTokenizers.UNDERSCORE) 23 | .addValueReader(new RecordValueReader()); 24 | 25 | return mapper; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /jooq-advanced/src/test/java/com/sightstudio/jooq/domain/book/BookRepoTest.java: -------------------------------------------------------------------------------- 1 | package com.sightstudio.jooq.domain.book; 2 | 3 | import com.sightstudio.jooq.app.domain.book.BookRepository; 4 | import com.sightstudio.jooq.config.JooqRepoTest; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Import; 7 | 8 | 9 | @Import(BookRepository.class) 10 | public class BookRepoTest extends JooqRepoTest { 11 | 12 | @Autowired 13 | private BookRepository bookRepository; 14 | } 15 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/DependentSubqueryApplication.java: -------------------------------------------------------------------------------- 1 | package com.sight.application; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DependentSubqueryApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DependentSubqueryApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/app/dco/OrderBy.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.dco; 2 | 3 | public enum OrderBy { 4 | DESC, ASC 5 | } 6 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/app/domain/board/BoardDetailDto.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.domain.board; 2 | 3 | import java.time.LocalDateTime; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | public class BoardDetailDto { 10 | private Long boardSeq; 11 | private Long boardTypeSeq; 12 | private Long userSeq; 13 | private String typeNm; 14 | private String userNm; 15 | private String title; 16 | private String content; 17 | private LocalDateTime regDate; 18 | } 19 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/app/domain/board/BoardSqlEdit.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.domain.board; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class BoardSqlEdit { 9 | private String title; 10 | private String content; 11 | } 12 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/app/domain/board/BoardSqlSearch.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.domain.board; 2 | 3 | import com.sight.application.app.dco.OrderBy; 4 | import com.sight.application.app.dto.OffsetPageSqlSearch; 5 | import java.time.LocalDate; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | public class BoardSqlSearch extends OffsetPageSqlSearch { 12 | private OrderBy orderBy = OrderBy.DESC; 13 | private LocalDate startDt = LocalDate.now(); 14 | private LocalDate finishDt = LocalDate.now(); 15 | private String titleKeyword = ""; 16 | private String contentKeyword = ""; 17 | } 18 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/app/dto/OffsetPageSqlSearch.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public abstract class OffsetPageSqlSearch { 9 | 10 | // 페이지는 1 부터 시작 11 | int page = 1; 12 | int pageSize = 30; 13 | 14 | public int getOffsetSize() { 15 | return (page - 1) * pageSize; 16 | } 17 | 18 | public int getLimit() { 19 | return pageSize; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/app/util/RandomUtil.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.util; 2 | 3 | import java.time.LocalDate; 4 | import java.time.LocalDateTime; 5 | import java.time.LocalTime; 6 | import java.util.concurrent.ThreadLocalRandom; 7 | 8 | public class RandomUtil { 9 | 10 | public static LocalDateTime getRandomDateTime(LocalDate dateStart, LocalDate dateEnd) { 11 | 12 | // [random date] 13 | long minDay = dateStart.toEpochDay(); 14 | long maxDay = dateEnd.toEpochDay(); 15 | 16 | long randomDay = ThreadLocalRandom.current().nextLong(minDay, maxDay); 17 | LocalDate randomDate = LocalDate.ofEpochDay(randomDay); 18 | 19 | // [random time] 20 | int startSeconds = LocalTime.of(0, 0).toSecondOfDay(); 21 | int endSeconds = LocalTime.of(23, 59).toSecondOfDay(); 22 | int randomTimeSecond = ThreadLocalRandom 23 | .current() 24 | .nextInt(startSeconds, endSeconds); 25 | LocalTime randomTime = LocalTime.ofSecondOfDay(randomTimeSecond); 26 | 27 | return LocalDateTime.of(randomDate, randomTime); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/config/jooq/BaseJooqRepository.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import com.sight.application.config.jooq.conditional.JooqDateTimeConditional; 4 | import com.sight.application.config.jooq.conditional.JooqListConditional; 5 | import com.sight.application.config.jooq.conditional.JooqNumberConditional; 6 | import com.sight.application.config.jooq.conditional.JooqSqlConditional; 7 | import com.sight.application.config.jooq.conditional.JooqTextConditional; 8 | 9 | public interface BaseJooqRepository extends JooqSqlConditional, JooqTextConditional, 10 | JooqNumberConditional, JooqListConditional, 11 | JooqDateTimeConditional { 12 | } 13 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/config/jooq/ExceptionTranslator.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import org.jooq.ExecuteContext; 4 | import org.jooq.SQLDialect; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; 7 | import org.springframework.jdbc.support.SQLExceptionTranslator; 8 | 9 | public class ExceptionTranslator extends DefaultExecuteListener { 10 | public void exception(ExecuteContext context) { 11 | SQLDialect dialect = context.configuration().dialect(); 12 | SQLExceptionTranslator translator = new SQLErrorCodeSQLExceptionTranslator(dialect.name()); 13 | 14 | context.exception(translator 15 | .translate("Access database using Jooq", context.sql(), context.sqlException())); 16 | } 17 | } -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/config/jooq/PerformanceListener.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.jooq.ExecuteContext; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.jooq.tools.StopWatch; 7 | 8 | @Slf4j 9 | public class PerformanceListener extends DefaultExecuteListener { 10 | 11 | private static final long MAX_ACCEPTABLE_QUERY_TIME = 5_000_000_000L; 12 | 13 | StopWatch watch; 14 | 15 | @Override 16 | public void executeStart(ExecuteContext ctx) { 17 | super.executeStart(ctx); 18 | watch = new StopWatch(); 19 | } 20 | 21 | @Override 22 | public void executeEnd(ExecuteContext ctx) { 23 | super.executeEnd(ctx); 24 | 25 | if (watch.split() > MAX_ACCEPTABLE_QUERY_TIME) { 26 | log.warn(String.format( 27 | """ 28 | Slow Query Detected: \n 29 | query: %s 30 | """, ctx.query()), new Exception()); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/config/jooq/TextSearchWildcard.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | public enum TextSearchWildcard { 4 | PREFIX, SUFFIX, FULL_TEXT, NONE 5 | } 6 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/config/jooq/conditional/JooqDateTimeConditional.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq.conditional; 2 | 3 | import java.time.LocalDate; 4 | import java.time.LocalDateTime; 5 | import org.jooq.Condition; 6 | import org.jooq.Record; 7 | import org.jooq.TableField; 8 | import org.jooq.impl.DSL; 9 | 10 | public interface JooqDateTimeConditional { 11 | default Condition nullableBetween(TableField dateTimeTableField, LocalDate startDt, LocalDate finishDt) { 12 | 13 | // 시작일 && 종료일 둘다 없으면 무시 14 | if (startDt == null && finishDt == null) { 15 | return DSL.noCondition(); 16 | } 17 | 18 | // 시작일만 존재하면 시작일 이후로 검색 19 | if (startDt != null && finishDt == null) { 20 | return dateTimeTableField.greaterOrEqual(startDt.atTime(0, 0)); 21 | } 22 | 23 | // 종료일만 존재하면 종료일 이전으로 검색 24 | if (startDt == null && finishDt != null) { 25 | return dateTimeTableField.lessOrEqual(finishDt.atTime(23, 59, 59)); 26 | } 27 | 28 | return dateTimeTableField.between(startDt.atTime(0, 0), finishDt.atTime(23, 59, 59)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/config/jooq/conditional/JooqListConditional.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq.conditional; 2 | 3 | import java.util.List; 4 | import org.jooq.Condition; 5 | import org.jooq.Record; 6 | import org.jooq.TableField; 7 | import org.jooq.impl.DSL; 8 | import org.springframework.util.CollectionUtils; 9 | 10 | public interface JooqListConditional { 11 | default Condition inIfNotEmpty(TableField columnVal, List paramVal) { 12 | if(CollectionUtils.isEmpty(paramVal)) { 13 | return DSL.noCondition(); 14 | } 15 | return columnVal.in(paramVal); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/config/jooq/conditional/JooqNumberConditional.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq.conditional; 2 | 3 | import org.jooq.Condition; 4 | import org.jooq.Record; 5 | import org.jooq.TableField; 6 | 7 | public interface JooqNumberConditional { 8 | default Condition eq (TableField column, TableField column2) { 9 | return column.eq(column2); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/config/jooq/conditional/JooqSqlConditional.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq.conditional; 2 | 3 | import com.sight.application.app.dco.OrderBy; 4 | import org.jooq.OrderField; 5 | import org.jooq.Record; 6 | import org.jooq.TableField; 7 | 8 | public interface JooqSqlConditional { 9 | default OrderField orderByField (TableField regDateTime, OrderBy orderBy) { 10 | if (orderBy == OrderBy.ASC) { 11 | return regDateTime.asc(); 12 | } 13 | 14 | if (orderBy == OrderBy.DESC) { 15 | return regDateTime.desc(); 16 | } 17 | return null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/web/BoardRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.web; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class BoardRegisterRequest { 11 | private String title; 12 | private String content; 13 | private Long boardTypeSeq; 14 | private Long userSeq; 15 | } 16 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/web/BoardTypeRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.web; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class BoardTypeRegisterRequest { 11 | private String code; 12 | private String codeName; 13 | } 14 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/java/com/sight/application/web/UserRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.web; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class UserRegisterRequest { 11 | private String userId; 12 | private String userName; 13 | } 14 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.url=jdbc:mysql://localhost:3306/jooq 3 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 4 | spring.datasource.username=root 5 | spring.datasource.password=passwd 6 | spring.jooq.sql-dialect=MySQL 7 | spring.jpa.properties.hibernate.format_sql= true 8 | spring.jpa.properties.hibernate.use_sql_comments= true 9 | logging.level.org.jooq.tools.LoggerListener=DEBUG -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.url=jdbc:mysql://localhost:3306/jooq 3 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 4 | spring.datasource.username=root 5 | spring.datasource.password=passwd 6 | spring.jpa.properties.hibernate.format_sql= true 7 | spring.jpa.properties.hibernate.use_sql_comments= true 8 | logging.level.org.jooq.tools.LoggerListener=DEBUG -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/main/resources/db-init.sql: -------------------------------------------------------------------------------- 1 | create table if not exists app_user 2 | ( 3 | user_seq int auto_increment 4 | primary key, 5 | user_id varchar(10) not null, 6 | user_name varchar(100) not null, 7 | constraint user_user_id_uindex 8 | unique (user_id) 9 | ); 10 | 11 | create table if not exists board 12 | ( 13 | board_seq bigint auto_increment 14 | primary key, 15 | title varchar(100) not null, 16 | content mediumtext not null, 17 | board_type_seq bigint not null, 18 | user_seq bigint not null, 19 | reg_date datetime null 20 | ); 21 | 22 | create index board_board_type_seq_index 23 | on board (board_type_seq); 24 | 25 | create index board_reg_date_index 26 | on board (reg_date); 27 | 28 | create index board_user_seq_index 29 | on board (user_seq); 30 | 31 | create table if not exists board_type 32 | ( 33 | board_type_seq bigint auto_increment 34 | primary key, 35 | code varchar(30) null, 36 | code_name varchar(30) null, 37 | constraint board_type_code_uindex 38 | unique (code) 39 | ); 40 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/test/java/com/sight/application/config/AppProfile.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config; 2 | 3 | public interface AppProfile { 4 | String PROD = "prod"; 5 | String TEST = "test"; 6 | } 7 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/test/java/com/sight/application/config/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config; 2 | 3 | import org.springframework.boot.test.context.SpringBootTest; 4 | import org.springframework.context.annotation.Profile; 5 | 6 | @Profile(AppProfile.TEST) 7 | @SpringBootTest 8 | public abstract class IntegrationTest { } 9 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/test/java/com/sight/application/config/JooqRepoTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config; 2 | 3 | import com.sight.application.config.jooq.JooqTestConfig; 4 | import org.springframework.boot.test.autoconfigure.jooq.JooqTest; 5 | import org.springframework.context.annotation.Import; 6 | import org.springframework.context.annotation.Profile; 7 | 8 | @Import(JooqTestConfig.class) 9 | @Profile(AppProfile.TEST) 10 | @JooqTest 11 | public abstract class JooqRepoTest { } 12 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/application/src/test/java/com/sight/application/config/jooq/JooqTestConfig.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import org.modelmapper.ModelMapper; 4 | import org.modelmapper.convention.NameTokenizers; 5 | import org.modelmapper.jooq.RecordValueReader; 6 | import org.modelmapper.module.jdk8.Jdk8Module; 7 | import org.modelmapper.module.jsr310.Jsr310Module; 8 | import org.springframework.boot.test.context.TestConfiguration; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | @TestConfiguration 12 | public class JooqTestConfig { 13 | 14 | @Bean 15 | public ModelMapper modelMapper() { 16 | ModelMapper mapper = new ModelMapper(); 17 | mapper.registerModule(new Jsr310Module()); 18 | mapper.registerModule(new Jdk8Module()); 19 | 20 | mapper.getConfiguration() 21 | .setSourceNameTokenizer(NameTokenizers.UNDERSCORE) 22 | .addValueReader(new RecordValueReader()); 23 | 24 | return mapper; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | jooq-db-mysql: 4 | image: mysql:8.0.27 5 | volumes: 6 | - test_volume:/data 7 | ports: 8 | - '3306:3306' 9 | environment: 10 | MYSQL_ROOT_PASSWORD: passwd 11 | MYSQL_DATABASE: jooq 12 | command: 13 | ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] 14 | 15 | volumes: 16 | test_volume: -------------------------------------------------------------------------------- /jooq-codegen-with-entity/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-codegen-with-entity/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /jooq-codegen-with-entity/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/jooq-custom/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/jooq-custom/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { id 'nu.studer.jooq' } 2 | bootJar { enabled = false } 3 | jar { enabled = true } 4 | 5 | dependencies { 6 | implementation project(':jooq-entity') 7 | implementation "org.jooq:jooq-codegen:${jooqVersion}" 8 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 9 | } -------------------------------------------------------------------------------- /jooq-codegen-with-entity/jooq-custom/src/main/java/jooq/custom/generator/JPrefixGeneratorStrategy.java: -------------------------------------------------------------------------------- 1 | package jooq.custom.generator; 2 | import org.jooq.codegen.DefaultGeneratorStrategy; 3 | import org.jooq.meta.Definition; 4 | 5 | public class JPrefixGeneratorStrategy extends DefaultGeneratorStrategy { 6 | 7 | @Override 8 | public String getJavaClassName(final Definition definition, final Mode mode) { 9 | if (mode == Mode.RECORD || mode == Mode.POJO || mode == Mode.DEFAULT) { 10 | return "J" + super.getJavaClassName(definition, mode); 11 | } 12 | return super.getJavaClassName(definition, mode); 13 | } 14 | 15 | 16 | } -------------------------------------------------------------------------------- /jooq-codegen-with-entity/jooq-entity/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/jooq-entity/build.gradle: -------------------------------------------------------------------------------- 1 | bootJar { enabled = false } 2 | jar { enabled = true } 3 | 4 | dependencies { 5 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 6 | implementation 'org.hibernate:hibernate-core-jakarta:5.6.7.Final' 7 | implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.0' 8 | implementation 'jakarta.persistence:jakarta.persistence-api:3.1.0' 9 | compileOnly 'org.projectlombok:lombok' 10 | annotationProcessor 'org.projectlombok:lombok' 11 | testCompileOnly 'org.projectlombok:lombok' 12 | testAnnotationProcessor 'org.projectlombok:lombok' 13 | } -------------------------------------------------------------------------------- /jooq-codegen-with-entity/jooq-entity/src/main/java/com/sight/entity/AppUser.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @Getter 9 | @Setter 10 | @Entity 11 | @Table(name = "app_user") 12 | @NoArgsConstructor 13 | public class AppUser { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | @Column(name = "user_seq", nullable = false) 18 | private Long userSeq; 19 | 20 | @Column(name = "user_id", nullable = false, unique = true) 21 | private String userId; 22 | 23 | @Column(name = "user_name", nullable = false) 24 | private String userName; 25 | } 26 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/jooq-entity/src/main/java/com/sight/entity/BoardType.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | 9 | @Getter 10 | @Setter 11 | @Entity 12 | @Table(name = "board_type") 13 | @NoArgsConstructor 14 | public class BoardType { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | @Column(name = "board_type_seq", nullable = false) 19 | private Long boardTypeSeq; 20 | 21 | @Column(name = "code", nullable = false) 22 | private String code; 23 | 24 | @Column(name = "code_name", nullable = false) 25 | private String codeName; 26 | } 27 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/jooq-entity/src/main/java/com/sight/entity/common/HistoryRequiredEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity.common; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.EntityListeners; 5 | import jakarta.persistence.MappedSuperclass; 6 | import lombok.Setter; 7 | import org.springframework.data.annotation.CreatedDate; 8 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 9 | 10 | import java.time.LocalDateTime; 11 | 12 | @EntityListeners(AuditingEntityListener.class) 13 | @MappedSuperclass 14 | public class HistoryRequiredEntity { 15 | 16 | @CreatedDate 17 | @Column(name = "reg_date") 18 | LocalDateTime regDate; 19 | } 20 | -------------------------------------------------------------------------------- /jooq-codegen-with-entity/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jooq-codegen-with-entity' 2 | include 'jooq-custom' 3 | include 'jooq-entity' 4 | include 'application' -------------------------------------------------------------------------------- /jooq-sight-demo/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /jooq-sight-demo/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-sight-demo/README.md -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-jpa/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | out/ 16 | !**/src/main/**/out/ 17 | !**/src/test/**/out/ 18 | 19 | ### Eclipse ### 20 | .apt_generated 21 | .classpath 22 | .factorypath 23 | .project 24 | .settings 25 | .springBeans 26 | .sts4-cache 27 | bin/ 28 | !**/src/main/**/bin/ 29 | !**/src/test/**/bin/ 30 | 31 | ### NetBeans ### 32 | /nbproject/private/ 33 | /nbbuild/ 34 | /dist/ 35 | /nbdist/ 36 | /.nb-gradle/ 37 | 38 | ### VS Code ### 39 | .vscode/ 40 | 41 | ### Mac OS ### 42 | .DS_Store -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-jpa/src/main/java/com/sight/application/jpa/JooqJpaDSLDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.jpa; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JooqJpaDSLDemoApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(JooqJpaDSLDemoApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-jpa/src/main/java/com/sight/application/jpa/config/jooq/ExceptionTranslator.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.jpa.config.jooq; 2 | 3 | import org.jooq.ExecuteContext; 4 | import org.jooq.SQLDialect; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; 7 | import org.springframework.jdbc.support.SQLExceptionTranslator; 8 | 9 | public class ExceptionTranslator extends DefaultExecuteListener { 10 | public void exception(ExecuteContext context) { 11 | SQLDialect dialect = context.configuration().dialect(); 12 | SQLExceptionTranslator translator = new SQLErrorCodeSQLExceptionTranslator(dialect.name()); 13 | 14 | context.exception(translator 15 | .translate("Access database using Jooq", context.sql(), context.sqlException())); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-jpa/src/main/java/com/sight/application/jpa/config/jooq/PerformanceListener.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.jpa.config.jooq; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.jooq.ExecuteContext; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.jooq.tools.StopWatch; 7 | 8 | @Slf4j 9 | public class PerformanceListener extends DefaultExecuteListener { 10 | 11 | StopWatch watch; 12 | 13 | @Override 14 | public void executeStart(ExecuteContext ctx) { 15 | super.executeStart(ctx); 16 | watch = new StopWatch(); 17 | } 18 | 19 | @Override 20 | public void executeEnd(ExecuteContext ctx) { 21 | super.executeEnd(ctx); 22 | if (watch.split() > 5_000_000_000L) 23 | log.warn("Slow Query Detected: \n" + ctx.query(), new Exception()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-jpa/src/main/java/com/sight/application/jpa/config/jooq/conditions/JooqBaseCondition.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.jpa.config.jooq.conditions; 2 | 3 | import org.jooq.Condition; 4 | import org.jooq.Field; 5 | import org.jooq.impl.DSL; 6 | 7 | public class JooqBaseCondition { 8 | 9 | public static Condition eq (Field field1, Field field2) { 10 | return field1.eq(field2); 11 | } 12 | 13 | public static Condition eq (Field field1, T value) { 14 | return field1.eq(value); 15 | } 16 | 17 | public static Condition eqIfNotNUll (Field field1, T value) { 18 | if (value == null) { 19 | return DSL.noCondition(); 20 | } 21 | return field1.eq(value); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-jpa/src/main/java/com/sight/application/jpa/config/jooq/conditions/JooqStringCondition.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.jpa.config.jooq.conditions; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.jooq.Condition; 5 | import org.jooq.Field; 6 | import org.jooq.impl.DSL; 7 | 8 | public class JooqStringCondition { 9 | 10 | public static Condition eqIfNotBlank (Field field1, String value) { 11 | if (StringUtils.isBlank(value)) { 12 | return DSL.noCondition(); 13 | } 14 | return field1.eq(value); 15 | } 16 | 17 | public static Condition eqIgnoreCaseIfNotNUll (Field field1, String value) { 18 | if (StringUtils.isBlank(value)) { 19 | return DSL.noCondition(); 20 | } 21 | return field1.equalIgnoreCase(value); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-jpa/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://localhost:3306/sakila 2 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 3 | spring.datasource.username=root 4 | spring.datasource.password=passwd 5 | 6 | spring.jpa.properties.hibernate.format_sql=true 7 | spring.jpa.show-sql=true 8 | spring.jpa.hibernate.ddl-auto=none 9 | spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect 10 | 11 | spring.jooq.sql-dialect=MySQL 12 | 13 | logging.level.org.jooq.tools.LoggerListener=DEBUG 14 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/java/com/sight/application/tc/JooqTcDSLApplication.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JooqTcDSLApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(JooqTcDSLApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/java/com/sight/application/tc/config/jooq/ExceptionTranslator.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc.config.jooq; 2 | 3 | import org.jooq.ExecuteContext; 4 | import org.jooq.SQLDialect; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; 7 | import org.springframework.jdbc.support.SQLExceptionTranslator; 8 | 9 | public class ExceptionTranslator extends DefaultExecuteListener { 10 | public void exception(ExecuteContext context) { 11 | SQLDialect dialect = context.configuration().dialect(); 12 | SQLExceptionTranslator translator = new SQLErrorCodeSQLExceptionTranslator(dialect.name()); 13 | 14 | context.exception(translator 15 | .translate("Access database using Jooq", context.sql(), context.sqlException())); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/java/com/sight/application/tc/config/jooq/PerformanceListener.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc.config.jooq; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.jooq.ExecuteContext; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.jooq.tools.StopWatch; 7 | 8 | @Slf4j 9 | public class PerformanceListener extends DefaultExecuteListener { 10 | 11 | StopWatch watch; 12 | 13 | @Override 14 | public void executeStart(ExecuteContext ctx) { 15 | super.executeStart(ctx); 16 | watch = new StopWatch(); 17 | } 18 | 19 | @Override 20 | public void executeEnd(ExecuteContext ctx) { 21 | super.executeEnd(ctx); 22 | if (watch.split() > 5_000_000_000L) 23 | log.warn("Slow Query Detected: \n" + ctx.query(), new Exception()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/java/com/sight/application/tc/config/jooq/meta/conditions/JooqBaseCondition.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc.config.jooq.meta.conditions; 2 | 3 | import org.jooq.Condition; 4 | import org.jooq.Field; 5 | import org.jooq.impl.DSL; 6 | 7 | public class JooqBaseCondition { 8 | 9 | public static Condition eq (Field field1, Field field2) { 10 | return field1.eq(field2); 11 | } 12 | 13 | public static Condition eq (Field field1, T value) { 14 | return field1.eq(value); 15 | } 16 | 17 | public static Condition eqIfNotNUll (Field field1, T value) { 18 | if (value == null) { 19 | return DSL.noCondition(); 20 | } 21 | return field1.eq(value); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/java/com/sight/application/tc/config/jooq/meta/conditions/JooqStringCondition.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc.config.jooq.meta.conditions; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.jooq.Condition; 5 | import org.jooq.Field; 6 | import org.jooq.impl.DSL; 7 | 8 | public class JooqStringCondition { 9 | 10 | public static Condition eqIfNotBlank (Field field1, String value) { 11 | if (StringUtils.isBlank(value)) { 12 | return DSL.noCondition(); 13 | } 14 | return field1.eq(value); 15 | } 16 | 17 | public static Condition eqIgnoreCaseIfNotNUll (Field field1, String value) { 18 | if (StringUtils.isBlank(value)) { 19 | return DSL.noCondition(); 20 | } 21 | return field1.equalIgnoreCase(value); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/java/com/sight/application/tc/dtos/CategorySummaryDto.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc.dtos; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | 6 | @Getter 7 | @RequiredArgsConstructor 8 | public class CategorySummaryDto { 9 | private Long filmId; 10 | private Long categoryId; 11 | private String title; 12 | private String name; 13 | } 14 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/java/com/sight/application/tc/dtos/FilmSummaryDto.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc.dtos; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | 6 | @Getter 7 | @RequiredArgsConstructor 8 | public class FilmSummaryDto { 9 | private Long filmId; 10 | private String title; 11 | private String actors; 12 | } 13 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/java/com/sight/application/tc/service/FilmService.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc.service; 2 | 3 | import com.sight.application.tc.repository.FilmJooqRepository; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service 8 | @RequiredArgsConstructor 9 | public class FilmService { 10 | 11 | private final FilmJooqRepository dao; 12 | 13 | public void test() { 14 | // dao.findById() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://localhost:3306/sakila 2 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 3 | spring.datasource.username=root 4 | spring.datasource.password=passwd 5 | 6 | spring.jpa.properties.hibernate.format_sql=true 7 | spring.jpa.show-sql=true 8 | spring.jpa.hibernate.ddl-auto=none 9 | spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect 10 | 11 | spring.jooq.sql-dialect=MySQL 12 | spring.flyway.enabled=false 13 | 14 | logging.level.org.jooq.tools.LoggerListener=DEBUG 15 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/resources/db/mysql-sakila-delete-data.sql: -------------------------------------------------------------------------------- 1 | -- Delete data 2 | ALTER TABLE staff DROP FOREIGN KEY fk_staff_store , DROP FOREIGN KEY fk_staff_address; 3 | DELETE FROM payment ; 4 | DELETE FROM rental ; 5 | DELETE FROM customer ; 6 | DELETE FROM film_category ; 7 | DELETE FROM film_text ; 8 | DELETE FROM film_actor ; 9 | DELETE FROM inventory ; 10 | DELETE FROM film ; 11 | DELETE FROM category ; 12 | ALTER TABLE store CHANGE COLUMN manager_staff_id manager_staff_id TINYINT UNSIGNED NULL; 13 | update store set manager_staff_id=null; 14 | DELETE FROM staff ; 15 | DELETE FROM store ; 16 | DELETE FROM actor ; 17 | DELETE FROM address ; 18 | DELETE FROM city ; 19 | DELETE FROM country ; 20 | DELETE FROM language ; 21 | ALTER TABLE store CHANGE COLUMN manager_staff_id manager_staff_id TINYINT UNSIGNED NOT NULL; 22 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/main/resources/db/mysql-sakila-drop-objects.sql: -------------------------------------------------------------------------------- 1 | -- Drop Views 2 | 3 | DROP VIEW customer_list; 4 | DROP VIEW film_list; 5 | DROP VIEW nicer_but_slower_film_list; 6 | DROP VIEW sales_by_film_category; 7 | DROP VIEW sales_by_store; 8 | DROP VIEW staff_list; 9 | 10 | -- Drop Tables 11 | 12 | DROP TABLE payment; 13 | DROP TABLE rental; 14 | DROP TABLE inventory; 15 | DROP TABLE film_text; 16 | DROP TABLE film_category; 17 | DROP TABLE film_actor; 18 | DROP TABLE film; 19 | DROP TABLE language; 20 | DROP TABLE customer; 21 | DROP TABLE actor; 22 | DROP TABLE category; 23 | ALTER TABLE staff DROP FOREIGN KEY fk_staff_store , DROP FOREIGN KEY fk_staff_address; 24 | DROP TABLE store; 25 | DROP TABLE address; 26 | DROP TABLE staff; 27 | DROP TABLE city; 28 | DROP TABLE country; 29 | 30 | -- Procedures and views 31 | drop procedure film_in_stock; 32 | drop procedure film_not_in_stock; 33 | drop function get_customer_balance; 34 | drop function inventory_held_by_customer; 35 | drop function inventory_in_stock; 36 | drop procedure rewards_report; 37 | 38 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/test/java/com/sight/application/tc/CategoryJooqRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc; 2 | 3 | import com.sight.application.tc.config.IntegrationTest; 4 | import com.sight.application.tc.dtos.CategorySummaryDto; 5 | import com.sight.application.tc.dtos.FilmSummaryDto; 6 | import com.sight.application.tc.repository.CategoryJooqRepository; 7 | import com.sight.application.tc.repository.FilmJooqRepository; 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Disabled; 10 | import org.junit.jupiter.api.DisplayName; 11 | import org.junit.jupiter.api.Test; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | 14 | public class CategoryJooqRepositoryTest extends IntegrationTest { 15 | 16 | @Autowired 17 | CategoryJooqRepository jooqRepository; 18 | 19 | @Test 20 | @DisplayName("영화 요약정보 확인") 21 | @Disabled 22 | void test1() { 23 | // given 24 | String title = "ACADEMY DINOSAUR"; 25 | 26 | CategorySummaryDto filmSummary = jooqRepository.findCategorySummaryByTitle(title); 27 | 28 | Assertions.assertEquals(filmSummary.getTitle(), title); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/test/java/com/sight/application/tc/FilmRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc; 2 | 3 | import com.sight.application.tc.config.IntegrationTest; 4 | import com.sight.application.tc.dtos.FilmSummaryDto; 5 | import com.sight.application.tc.repository.FilmJooqRepository; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.Disabled; 8 | import org.junit.jupiter.api.DisplayName; 9 | import org.junit.jupiter.api.Test; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | public class FilmRepositoryTest extends IntegrationTest { 13 | 14 | @Autowired 15 | FilmJooqRepository jooqRepository; 16 | 17 | @Test 18 | @DisplayName("영화 요약정보 확인") 19 | @Disabled 20 | void test1() { 21 | // given 22 | String title = "ACADEMY DINOSAUR"; 23 | 24 | FilmSummaryDto filmSummary = jooqRepository.findFilmSummaryByTitle(title); 25 | 26 | Assertions.assertEquals(filmSummary.getTitle(), title); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/test/java/com/sight/application/tc/config/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc.config; 2 | 3 | import com.sight.application.tc.JooqTcDSLApplication; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | import org.springframework.transaction.annotation.Transactional; 6 | 7 | @SpringBootTest(classes = JooqTcDSLApplication.class) 8 | @Transactional 9 | public abstract class IntegrationTest { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /jooq-sight-demo/application-dsl-by-testcontainer/src/test/java/com/sight/application/tc/config/JooqRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.tc.config; 2 | 3 | import org.springframework.boot.test.autoconfigure.jooq.JooqTest; 4 | import org.springframework.transaction.annotation.Transactional; 5 | 6 | @JooqTest 7 | @Transactional 8 | public abstract class JooqRepositoryTest { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /jooq-sight-demo/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | jooq-db-mysql: 4 | image: mysql:8.0.27 5 | # uncomment this if you use m1 6 | platform: linux/amd64 7 | volumes: 8 | - test_volume:/data 9 | ports: 10 | - '3306:3306' 11 | environment: 12 | MYSQL_ROOT_PASSWORD: passwd 13 | MYSQL_DATABASE: sakila 14 | command: 15 | ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] 16 | volumes: 17 | test_volume: 18 | -------------------------------------------------------------------------------- /jooq-sight-demo/entity/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | out/ 16 | !**/src/main/**/out/ 17 | !**/src/test/**/out/ 18 | 19 | ### Eclipse ### 20 | .apt_generated 21 | .classpath 22 | .factorypath 23 | .project 24 | .settings 25 | .springBeans 26 | .sts4-cache 27 | bin/ 28 | !**/src/main/**/bin/ 29 | !**/src/test/**/bin/ 30 | 31 | ### NetBeans ### 32 | /nbproject/private/ 33 | /nbbuild/ 34 | /dist/ 35 | /nbdist/ 36 | /.nb-gradle/ 37 | 38 | ### VS Code ### 39 | .vscode/ 40 | 41 | ### Mac OS ### 42 | .DS_Store -------------------------------------------------------------------------------- /jooq-sight-demo/entity/build.gradle: -------------------------------------------------------------------------------- 1 | bootJar { enabled = false } 2 | jar { enabled = true } 3 | 4 | dependencies { 5 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 6 | compileOnly 'org.projectlombok:lombok' 7 | annotationProcessor 'org.projectlombok:lombok' 8 | testCompileOnly 'org.projectlombok:lombok' 9 | testAnnotationProcessor 'org.projectlombok:lombok' 10 | } 11 | -------------------------------------------------------------------------------- /jooq-sight-demo/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-sight-demo/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /jooq-sight-demo/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /jooq-sight-demo/jooq-custom/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | out/ 16 | !**/src/main/**/out/ 17 | !**/src/test/**/out/ 18 | 19 | ### Eclipse ### 20 | .apt_generated 21 | .classpath 22 | .factorypath 23 | .project 24 | .settings 25 | .springBeans 26 | .sts4-cache 27 | bin/ 28 | !**/src/main/**/bin/ 29 | !**/src/test/**/bin/ 30 | 31 | ### NetBeans ### 32 | /nbproject/private/ 33 | /nbbuild/ 34 | /dist/ 35 | /nbdist/ 36 | /.nb-gradle/ 37 | 38 | ### VS Code ### 39 | .vscode/ 40 | 41 | ### Mac OS ### 42 | .DS_Store -------------------------------------------------------------------------------- /jooq-sight-demo/jooq-custom/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { id 'nu.studer.jooq' } 2 | bootJar { enabled = false } 3 | jar { enabled = true } 4 | 5 | dependencies { 6 | implementation project(':entity') 7 | implementation "org.jooq:jooq-codegen:${jooqVersion}" 8 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 9 | } 10 | -------------------------------------------------------------------------------- /jooq-sight-demo/jooq-custom/src/main/java/jooq/custom/generator/JPrefixGeneratorStrategy.java: -------------------------------------------------------------------------------- 1 | package jooq.custom.generator; 2 | import org.jooq.codegen.DefaultGeneratorStrategy; 3 | import org.jooq.meta.Definition; 4 | 5 | public class JPrefixGeneratorStrategy extends DefaultGeneratorStrategy { 6 | 7 | @Override 8 | public String getJavaClassName(final Definition definition, final Mode mode) { 9 | if (mode == Mode.DEFAULT || mode == Mode.POJO || mode == Mode.RECORD) { 10 | return "J" + super.getJavaClassName(definition, mode); 11 | } 12 | return super.getJavaClassName(definition, mode); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /jooq-sight-demo/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jooq-sight-demo' 2 | include 'jooq-custom' 3 | include 'entity' 4 | include 'application-dsl-by-testcontainer' 5 | include 'application-dsl-by-jpa' 6 | 7 | -------------------------------------------------------------------------------- /jooq-start/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /jooq-start/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | maria-db: 4 | container_name: jooq 5 | image: mariadb:10.4 6 | volumes: 7 | - ./infra/volumes/mariadb:/data 8 | ports: 9 | - '3306:3306' 10 | environment: 11 | MYSQL_ROOT_PASSWORD: passwd 12 | MYSQL_DATABASE: jooq 13 | command: 14 | ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] -------------------------------------------------------------------------------- /jooq-start/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-start/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /jooq-start/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /jooq-start/jooq.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-start/jooq.gradle -------------------------------------------------------------------------------- /jooq-start/md-asset/1-test-code.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-start/md-asset/1-test-code.PNG -------------------------------------------------------------------------------- /jooq-start/md-asset/2-returning-insert.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-start/md-asset/2-returning-insert.PNG -------------------------------------------------------------------------------- /jooq-start/md-asset/3-select-delete.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-start/md-asset/3-select-delete.PNG -------------------------------------------------------------------------------- /jooq-start/md-asset/4-join-query.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-start/md-asset/4-join-query.PNG -------------------------------------------------------------------------------- /jooq-start/md-asset/5-dtos.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-start/md-asset/5-dtos.PNG -------------------------------------------------------------------------------- /jooq-start/md-asset/6-join-dto.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-start/md-asset/6-join-dto.PNG -------------------------------------------------------------------------------- /jooq-start/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jooq-start' 2 | -------------------------------------------------------------------------------- /jooq-start/src/main/java/com/sight/jooqstart/JooqStartApplication.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JooqStartApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JooqStartApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jooq-start/src/main/java/com/sight/jooqstart/app/domain/author/AuthorBookDto.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.app.domain.author; 2 | 3 | import com.sight.jooqstart.app.domain.book.BookDto; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | @Getter 8 | @Setter 9 | public class AuthorBookDto { 10 | private BookDto book; 11 | private AuthorDto author; 12 | } 13 | -------------------------------------------------------------------------------- /jooq-start/src/main/java/com/sight/jooqstart/app/domain/author/AuthorDto.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.app.domain.author; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.time.LocalDate; 7 | 8 | @Getter 9 | @Setter 10 | public class AuthorDto { 11 | 12 | private Integer id; 13 | private String firstName; 14 | private String lastName; 15 | 16 | private LocalDate dateOfBirth; 17 | private Integer yearOfBirth; 18 | 19 | private Boolean distinguished; 20 | 21 | public AuthorDto() { } 22 | 23 | public AuthorDto(String firstName, String lastName, LocalDate dateOfBirth, Integer yearOfBirth) { 24 | this.firstName = firstName; 25 | this.lastName = lastName; 26 | this.dateOfBirth = dateOfBirth; 27 | this.yearOfBirth = yearOfBirth; 28 | this.distinguished = true; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jooq-start/src/main/java/com/sight/jooqstart/app/domain/book/BookDto.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.app.domain.book; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | @Getter 7 | @Setter 8 | public class BookDto { 9 | private Integer id; 10 | private Integer authorId; 11 | private String title; 12 | private Integer publishedIn; 13 | private Integer languageId; 14 | } 15 | -------------------------------------------------------------------------------- /jooq-start/src/main/java/com/sight/jooqstart/app/domain/book/BookRepository.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.app.domain.book; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.jooq.DSLContext; 5 | import org.modelmapper.ModelMapper; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | @RequiredArgsConstructor 10 | public class BookRepository { 11 | private final DSLContext dsl; 12 | private final ModelMapper mapper; 13 | } -------------------------------------------------------------------------------- /jooq-start/src/main/java/com/sight/jooqstart/config/jooq/JooqConfig.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.config.jooq; 2 | 3 | import org.jooq.impl.DefaultDSLContext; 4 | import org.modelmapper.ModelMapper; 5 | import org.modelmapper.convention.NameTokenizers; 6 | import org.modelmapper.jooq.RecordValueReader; 7 | import org.modelmapper.module.jdk8.Jdk8Module; 8 | import org.modelmapper.module.jsr310.Jsr310Module; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | @Configuration 13 | public class JooqConfig { 14 | 15 | @Bean 16 | public DefaultDSLContext dslContext(org.jooq.Configuration configuration) { 17 | return new DefaultDSLContext(configuration); 18 | } 19 | 20 | @Bean 21 | public ModelMapper modelMapper() { 22 | ModelMapper mapper = new ModelMapper(); 23 | mapper.registerModule(new Jsr310Module()); 24 | mapper.registerModule(new Jdk8Module()); 25 | mapper.getConfiguration() 26 | .setSourceNameTokenizer(NameTokenizers.UNDERSCORE) 27 | .addValueReader(new RecordValueReader()); 28 | 29 | 30 | return mapper; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /jooq-start/src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.url=jdbc:mariadb://localhost:3306/jooq 3 | spring.datasource.driverClassName=org.mariadb.jdbc.Driver 4 | spring.datasource.username=root 5 | spring.datasource.password=passwd 6 | -------------------------------------------------------------------------------- /jooq-start/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.url=jdbc:mariadb://localhost:3306/jooq 3 | spring.datasource.driverClassName=org.mariadb.jdbc.Driver 4 | spring.datasource.username=root 5 | spring.datasource.password=passwd 6 | 7 | logging.level.org.jooq.tools.LoggerListener=DEBUG -------------------------------------------------------------------------------- /jooq-start/src/main/resources/sql/seed.sql: -------------------------------------------------------------------------------- 1 | insert into jooq.author (first_name, last_name, date_of_birth, year_of_birth, distinguished) 2 | values ('George', 'Orwell', '1903-06-26', 1903, null), 3 | ('Paulo', 'Coelho', '1947-08-24', 1947, null); 4 | 5 | insert into jooq.language (cd, description) 6 | values ('en', 'English'), 7 | ('de', 'Deutsch'), 8 | ('fr', 'Français'), 9 | ('pt', 'Português'); 10 | 11 | insert into jooq.book (author_id, title, published_in, language_id) 12 | values (1, '1984', 1948, 1), 13 | (1, 'Animal Farm', 1945, 1), 14 | (2, 'O Alquimista', 1988, 4), 15 | (2, 'Brida', 1990, 2); 16 | 17 | 18 | insert into jooq.book_store (name) 19 | values ('Buchhandlung im Volkshaus'), 20 | ('Ex Libris'), 21 | ('Orell Füssli'); 22 | 23 | insert into jooq.book_to_book_store (name, book_id, stock) 24 | values ('Buchhandlung im Volkshaus', 3, 1), 25 | ('Ex Libris', 1, 1), 26 | ('Ex Libris', 3, 2), 27 | ('Orell Füssli', 1, 10), 28 | ('Orell Füssli', 2, 10), 29 | ('Orell Füssli', 3, 10); -------------------------------------------------------------------------------- /jooq-start/src/test/java/com/sight/jooqstart/config/AppProfile.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.config; 2 | 3 | public interface AppProfile { 4 | String PROD = "prod"; 5 | String TEST = "test"; 6 | } 7 | -------------------------------------------------------------------------------- /jooq-start/src/test/java/com/sight/jooqstart/config/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.config; 2 | 3 | import org.springframework.boot.test.context.SpringBootTest; 4 | import org.springframework.context.annotation.Profile; 5 | import org.springframework.transaction.annotation.Transactional; 6 | 7 | @Profile(AppProfile.TEST) 8 | @Transactional 9 | @SpringBootTest 10 | public abstract class IntegrationTest { } 11 | -------------------------------------------------------------------------------- /jooq-start/src/test/java/com/sight/jooqstart/config/JooqRepoTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.config; 2 | 3 | import com.sight.jooqstart.config.jooq.JooqTestConfig; 4 | import org.springframework.boot.test.autoconfigure.jooq.JooqTest; 5 | import org.springframework.context.annotation.Import; 6 | import org.springframework.context.annotation.Profile; 7 | import org.springframework.transaction.annotation.Transactional; 8 | 9 | @Import(JooqTestConfig.class) 10 | @Profile(AppProfile.TEST) 11 | @Transactional 12 | @JooqTest 13 | public abstract class JooqRepoTest { } 14 | -------------------------------------------------------------------------------- /jooq-start/src/test/java/com/sight/jooqstart/config/jooq/JooqTestConfig.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.config.jooq; 2 | 3 | import org.modelmapper.ModelMapper; 4 | import org.modelmapper.convention.NameTokenizers; 5 | import org.modelmapper.jooq.RecordValueReader; 6 | import org.modelmapper.module.jdk8.Jdk8Module; 7 | import org.modelmapper.module.jsr310.Jsr310Module; 8 | import org.springframework.boot.test.context.TestConfiguration; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | @TestConfiguration 12 | public class JooqTestConfig { 13 | 14 | @Bean 15 | public ModelMapper modelMapper() { 16 | ModelMapper mapper = new ModelMapper(); 17 | mapper.registerModule(new Jsr310Module()); 18 | mapper.registerModule(new Jdk8Module()); 19 | 20 | mapper.getConfiguration() 21 | .setSourceNameTokenizer(NameTokenizers.UNDERSCORE) 22 | .addValueReader(new RecordValueReader()); 23 | 24 | return mapper; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /jooq-start/src/test/java/com/sight/jooqstart/domain/book/BookRepoTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.jooqstart.domain.book; 2 | 3 | import com.sight.jooqstart.app.domain.book.BookRepository; 4 | import com.sight.jooqstart.config.JooqRepoTest; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Import; 7 | 8 | 9 | @Import(BookRepository.class) 10 | public class BookRepoTest extends JooqRepoTest { 11 | 12 | @Autowired 13 | private BookRepository bookRepository; 14 | } 15 | -------------------------------------------------------------------------------- /jooq-with-jpa/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /jooq-with-jpa/Dockerfile: -------------------------------------------------------------------------------- 1 | # Non M1 2 | # FROM amazoncorretto:17-alpine-jdk 3 | 4 | # M1 5 | FROM amd64/amazoncorretto:17-alpine-jdk 6 | 7 | EXPOSE 8080 8 | 9 | ENTRYPOINT ["java","-jar","/applicaition.jar"] 10 | VOLUME /tmp 11 | ARG JAR_FILE=application/build/libs/application.jar 12 | COPY ${JAR_FILE} app.jar 13 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] -------------------------------------------------------------------------------- /jooq-with-jpa/application/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/JooqWithJpa.java: -------------------------------------------------------------------------------- 1 | package com.sight.application; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JooqWithJpa { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JooqWithJpa.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/app/domain/board/BoardJpaRepository.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.domain.board; 2 | 3 | import com.sight.entity.Board; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface BoardJpaRepository extends JpaRepository { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/app/domain/board/type/BoardTypeJpaRepository.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.domain.board.type; 2 | 3 | import com.sight.entity.BoardType; 4 | import java.util.List; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface BoardTypeJpaRepository extends JpaRepository { 10 | 11 | List findByCodeNameContaining(String codeName); 12 | } 13 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/app/util/RandomUtil.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.app.util; 2 | 3 | import java.time.LocalDate; 4 | import java.time.LocalDateTime; 5 | import java.time.LocalTime; 6 | import java.util.concurrent.ThreadLocalRandom; 7 | 8 | public class RandomUtil { 9 | 10 | public static LocalDateTime getRandomDateTime(LocalDate dateStart, LocalDate dateEnd) { 11 | 12 | // [random date] 13 | long minDay = dateStart.toEpochDay(); 14 | long maxDay = dateEnd.toEpochDay(); 15 | 16 | long randomDay = ThreadLocalRandom.current().nextLong(minDay, maxDay); 17 | LocalDate randomDate = LocalDate.ofEpochDay(randomDay); 18 | 19 | // [random time] 20 | int startSeconds = LocalTime.of(0, 0).toSecondOfDay(); 21 | int endSeconds = LocalTime.of(23, 59).toSecondOfDay(); 22 | int randomTimeSecond = ThreadLocalRandom 23 | .current() 24 | .nextInt(startSeconds, endSeconds); 25 | LocalTime randomTime = LocalTime.ofSecondOfDay(randomTimeSecond); 26 | 27 | return LocalDateTime.of(randomDate, randomTime); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/config/jooq/ExceptionTranslator.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import org.jooq.ExecuteContext; 4 | import org.jooq.SQLDialect; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator; 7 | import org.springframework.jdbc.support.SQLExceptionTranslator; 8 | 9 | public class ExceptionTranslator extends DefaultExecuteListener { 10 | public void exception(ExecuteContext context) { 11 | SQLDialect dialect = context.configuration().dialect(); 12 | SQLExceptionTranslator translator = new SQLErrorCodeSQLExceptionTranslator(dialect.name()); 13 | 14 | context.exception(translator 15 | .translate("Access database using Jooq", context.sql(), context.sqlException())); 16 | } 17 | } -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/config/jooq/PerformanceListener.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.jooq.ExecuteContext; 5 | import org.jooq.impl.DefaultExecuteListener; 6 | import org.jooq.tools.StopWatch; 7 | 8 | @Slf4j 9 | public class PerformanceListener extends DefaultExecuteListener { 10 | 11 | StopWatch watch; 12 | 13 | @Override 14 | public void executeStart(ExecuteContext ctx) { 15 | super.executeStart(ctx); 16 | watch = new StopWatch(); 17 | } 18 | 19 | @Override 20 | public void executeEnd(ExecuteContext ctx) { 21 | super.executeEnd(ctx); 22 | if (watch.split() > 5_000_000_000L) 23 | log.warn("Slow Query Detected: \n" + ctx.query(), new Exception()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/config/jooq/TextSearchWildcard.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | public enum TextSearchWildcard { 4 | PREFIX, SUFFIX, FULL_TEXT, NONE 5 | } 6 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/dto/BoardRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class BoardRegisterRequest { 11 | private String title; 12 | private String content; 13 | private Long boardTypeSeq; 14 | private Long userSeq; 15 | } 16 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/dto/BoardTypeDto.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.dto; 2 | 3 | import com.sight.entity.BoardType; 4 | import javax.persistence.Column; 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.GenerationType; 8 | import javax.persistence.Id; 9 | import javax.persistence.Table; 10 | import lombok.Getter; 11 | import lombok.NoArgsConstructor; 12 | import lombok.Setter; 13 | 14 | 15 | @Getter 16 | @Setter 17 | @NoArgsConstructor 18 | public class BoardTypeDto { 19 | 20 | private Long boardTypeSeq; 21 | 22 | private String code; 23 | 24 | private String codeName; 25 | 26 | public BoardTypeDto(BoardType boardType) { 27 | this.boardTypeSeq = boardType.getBoardTypeSeq(); 28 | this.code = boardType.getCode(); 29 | this.codeName = boardType.getCodeName(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/dto/BoardTypeRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class BoardTypeRegisterRequest { 11 | private String code; 12 | private String codeName; 13 | } 14 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/dto/UserRegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @NoArgsConstructor 9 | @AllArgsConstructor 10 | public class UserRegisterRequest { 11 | private String userId; 12 | private String userName; 13 | } 14 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/web/BoardController.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.web; 2 | 3 | import com.sight.application.app.domain.board.BoardService; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | @RequiredArgsConstructor 10 | public class BoardController { 11 | 12 | private final BoardService boardService; 13 | 14 | @GetMapping 15 | public void getBoardType() { 16 | 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/java/com/sight/application/web/BoardTypeController.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.web; 2 | 3 | import com.sight.application.app.domain.board.type.BoardTypeService; 4 | import com.sight.application.dto.BoardTypeDto; 5 | import com.sight.entity.BoardType; 6 | import java.util.List; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestParam; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @RestController 14 | @RequiredArgsConstructor 15 | @RequestMapping("/board-type") 16 | public class BoardTypeController { 17 | 18 | private final BoardTypeService boardTypeService; 19 | 20 | @GetMapping 21 | public List getBoardTypeLike(@RequestParam String keyword) { 22 | return boardTypeService.getBoardTypeByKeywordLike(keyword); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:mysql://localhost:3306/jooq 2 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 3 | spring.datasource.username=root 4 | spring.datasource.password=passwd 5 | 6 | spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect 7 | spring.jpa.properties.hibernate.format_sql=true 8 | spring.jpa.show-sql=true 9 | spring.jpa.hibernate.ddl-auto=none 10 | 11 | spring.jooq.sql-dialect=MySQL 12 | logging.level.org.jooq.tools.LoggerListener=DEBUG 13 | 14 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # for run container in local 2 | #spring.datasource.url=jdbc:mysql://jooq-db-mysql/jooq 3 | 4 | 5 | spring.datasource.url=jdbc:mysql://localhost:3306/jooq 6 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 7 | spring.datasource.username=root 8 | spring.datasource.password=passwd 9 | 10 | spring.jpa.properties.hibernate.format_sql=true 11 | spring.jpa.show-sql=true 12 | spring.jpa.hibernate.ddl-auto=none 13 | spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect 14 | 15 | spring.jooq.sql-dialect=MySQL 16 | 17 | logging.level.org.jooq.tools.LoggerListener=DEBUG -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/test/java/com/sight/application/config/AppProfile.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config; 2 | 3 | public interface AppProfile { 4 | String PROD = "prod"; 5 | String TEST = "test"; 6 | } 7 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/test/java/com/sight/application/config/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config; 2 | 3 | import org.springframework.boot.test.context.SpringBootTest; 4 | import org.springframework.context.annotation.Profile; 5 | 6 | @Profile(AppProfile.TEST) 7 | @SpringBootTest 8 | public abstract class IntegrationTest { } 9 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/test/java/com/sight/application/config/JooqRepoTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config; 2 | 3 | import com.sight.application.config.jooq.JooqTestConfig; 4 | import org.springframework.boot.test.autoconfigure.jooq.JooqTest; 5 | import org.springframework.context.annotation.Import; 6 | import org.springframework.context.annotation.Profile; 7 | 8 | @Import(JooqTestConfig.class) 9 | @Profile(AppProfile.TEST) 10 | @JooqTest 11 | public abstract class JooqRepoTest { } 12 | -------------------------------------------------------------------------------- /jooq-with-jpa/application/src/test/java/com/sight/application/config/jooq/JooqTestConfig.java: -------------------------------------------------------------------------------- 1 | package com.sight.application.config.jooq; 2 | 3 | import org.modelmapper.ModelMapper; 4 | import org.modelmapper.convention.NameTokenizers; 5 | import org.modelmapper.jooq.RecordValueReader; 6 | import org.modelmapper.module.jdk8.Jdk8Module; 7 | import org.modelmapper.module.jsr310.Jsr310Module; 8 | import org.springframework.boot.test.context.TestConfiguration; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | @TestConfiguration 12 | public class JooqTestConfig { 13 | 14 | @Bean 15 | public ModelMapper modelMapper() { 16 | ModelMapper mapper = new ModelMapper(); 17 | mapper.registerModule(new Jsr310Module()); 18 | mapper.registerModule(new Jdk8Module()); 19 | 20 | mapper.getConfiguration() 21 | .setSourceNameTokenizer(NameTokenizers.UNDERSCORE) 22 | .addValueReader(new RecordValueReader()); 23 | 24 | return mapper; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /jooq-with-jpa/ddl.sql: -------------------------------------------------------------------------------- 1 | create table if not exists app_user ( 2 | user_seq bigint auto_increment primary key, 3 | user_id varchar(255) not null, 4 | user_name varchar(255) not null, 5 | constraint UK_qjho89hmbuv32f9a8tbocpr0i 6 | unique (user_id) 7 | ); 8 | 9 | create table if not exists board_type ( 10 | board_type_seq bigint auto_increment primary key, 11 | code varchar(255) not null, 12 | code_name varchar(255) not null 13 | ); 14 | 15 | create table if not exists board ( 16 | board_seq bigint auto_increment primary key, 17 | reg_date datetime(6) null, 18 | content varchar(255) not null, 19 | title varchar(255) not null, 20 | board_type_seq bigint not null, 21 | user_seq bigint not null, 22 | constraint FK1u7ywt94islad666xmdi4juxb 23 | foreign key (user_seq) references app_user (user_seq), 24 | constraint FK219u599g2m5uoup2vcvjiptka 25 | foreign key (board_type_seq) references board_type (board_type_seq) 26 | ); 27 | 28 | -------------------------------------------------------------------------------- /jooq-with-jpa/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | jooq-db-mysql: 4 | image: mysql:8.0.27 5 | # uncomment this if you use m1 6 | platform: linux/amd64 7 | volumes: 8 | - test_volume:/data 9 | ports: 10 | - '3306:3306' 11 | environment: 12 | MYSQL_ROOT_PASSWORD: passwd 13 | MYSQL_DATABASE: jooq 14 | command: 15 | ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] 16 | 17 | application: 18 | image: jooq-test 19 | ports: 20 | - '8080:8080' 21 | volumes: 22 | test_volume: -------------------------------------------------------------------------------- /jooq-with-jpa/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jooq-with-jpa/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /jooq-with-jpa/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /jooq-with-jpa/http/board.http: -------------------------------------------------------------------------------- 1 | GET {{server}}/board-type?keyword=a 2 | -------------------------------------------------------------------------------- /jooq-with-jpa/http/http-client.env.json: -------------------------------------------------------------------------------- 1 | { 2 | "local": { 3 | "server": "http://localhost:8080" 4 | } 5 | } -------------------------------------------------------------------------------- /jooq-with-jpa/jooq-custom/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /jooq-with-jpa/jooq-custom/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { id 'nu.studer.jooq' } 2 | bootJar { enabled = false } 3 | jar { enabled = true } 4 | 5 | dependencies { 6 | implementation project(':jooq-entity') 7 | implementation "org.jooq:jooq-codegen:${jooqVersion}" 8 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 9 | } -------------------------------------------------------------------------------- /jooq-with-jpa/jooq-custom/src/main/java/jooq/custom/generator/JPrefixGeneratorStrategy.java: -------------------------------------------------------------------------------- 1 | package jooq.custom.generator; 2 | import org.jooq.codegen.DefaultGeneratorStrategy; 3 | import org.jooq.meta.Definition; 4 | 5 | public class JPrefixGeneratorStrategy extends DefaultGeneratorStrategy { 6 | 7 | @Override 8 | public String getJavaClassName(final Definition definition, final Mode mode) { 9 | if (mode == Mode.RECORD || mode == Mode.POJO || mode == Mode.DEFAULT) { 10 | return "J" + super.getJavaClassName(definition, mode); 11 | } 12 | return super.getJavaClassName(definition, mode); 13 | } 14 | } -------------------------------------------------------------------------------- /jooq-with-jpa/jooq-entity/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | **/src/generated/** 8 | 9 | ### STS ### 10 | .apt_generated 11 | .classpath 12 | .factorypath 13 | .project 14 | .settings 15 | .springBeans 16 | .sts4-cache 17 | bin/ 18 | !**/src/main/**/bin/ 19 | !**/src/test/**/bin/ 20 | 21 | ### IntelliJ IDEA ### 22 | .idea 23 | *.iws 24 | *.iml 25 | *.ipr 26 | out/ 27 | !**/src/main/**/out/ 28 | !**/src/test/**/out/ 29 | 30 | ### NetBeans ### 31 | /nbproject/private/ 32 | /nbbuild/ 33 | /dist/ 34 | /nbdist/ 35 | /.nb-gradle/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | -------------------------------------------------------------------------------- /jooq-with-jpa/jooq-entity/build.gradle: -------------------------------------------------------------------------------- 1 | bootJar { enabled = false } 2 | jar { enabled = true } 3 | 4 | dependencies { 5 | implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 6 | implementation 'javax.persistence:javax.persistence-api:2.2' 7 | compileOnly 'org.projectlombok:lombok' 8 | annotationProcessor 'org.projectlombok:lombok' 9 | testCompileOnly 'org.projectlombok:lombok' 10 | testAnnotationProcessor 'org.projectlombok:lombok' 11 | } -------------------------------------------------------------------------------- /jooq-with-jpa/jooq-entity/src/main/java/com/sight/entity/AppUser.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity; 2 | 3 | import javax.persistence.*; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @Getter 9 | @Setter 10 | @Entity 11 | @Table(name = "app_user") 12 | @NoArgsConstructor 13 | public class AppUser { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.IDENTITY) 17 | @Column(name = "user_seq", nullable = false) 18 | private Long userSeq; 19 | 20 | @Column(name = "user_id", nullable = false, unique = true) 21 | private String userId; 22 | 23 | @Column(name = "user_name", nullable = false) 24 | private String userName; 25 | } 26 | -------------------------------------------------------------------------------- /jooq-with-jpa/jooq-entity/src/main/java/com/sight/entity/Board.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity; 2 | 3 | import com.sight.entity.common.HistoryRequiredEntity; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import javax.persistence.*; 8 | 9 | @Getter 10 | @Setter 11 | @Entity 12 | @Table(name = "board") 13 | @NoArgsConstructor 14 | public class Board extends HistoryRequiredEntity { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | @Column(name = "board_seq", nullable = false) 19 | private Long boardSeq; 20 | 21 | @Column(name = "title", nullable = false) 22 | private String title; 23 | 24 | @Column(name = "content", nullable = false) 25 | private String content; 26 | 27 | @ManyToOne(fetch = FetchType.LAZY) 28 | @JoinColumn(name = "board_type_seq", nullable = false) 29 | private BoardType boardType; 30 | 31 | @ManyToOne(fetch = FetchType.LAZY) 32 | @JoinColumn(name = "user_seq", nullable = false) 33 | private AppUser writer; 34 | } 35 | -------------------------------------------------------------------------------- /jooq-with-jpa/jooq-entity/src/main/java/com/sight/entity/BoardType.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity; 2 | 3 | import javax.persistence.*; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | 9 | @Getter 10 | @Setter 11 | @Entity 12 | @Table(name = "board_type") 13 | @NoArgsConstructor 14 | public class BoardType { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | @Column(name = "board_type_seq", nullable = false) 19 | private Long boardTypeSeq; 20 | 21 | @Column(name = "code", nullable = false) 22 | private String code; 23 | 24 | @Column(name = "code_name", nullable = false) 25 | private String codeName; 26 | } 27 | -------------------------------------------------------------------------------- /jooq-with-jpa/jooq-entity/src/main/java/com/sight/entity/common/HistoryRequiredEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.entity.common; 2 | 3 | import javax.persistence.*; 4 | import org.springframework.data.annotation.CreatedDate; 5 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 6 | 7 | import java.time.LocalDateTime; 8 | 9 | @EntityListeners(AuditingEntityListener.class) 10 | @MappedSuperclass 11 | public class HistoryRequiredEntity { 12 | 13 | @CreatedDate 14 | @Column(name = "reg_date") 15 | LocalDateTime regDate; 16 | } 17 | -------------------------------------------------------------------------------- /jooq-with-jpa/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jooq-with-jpa' 2 | include 'jooq-custom' 3 | include 'jooq-entity' 4 | include 'application' -------------------------------------------------------------------------------- /jpa-separate-ro-rw/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/README.md: -------------------------------------------------------------------------------- 1 | ### 스프링에서 편리하게 Master / Slave 분기 처리하기 2 | 3 | 요구 사항 4 | 5 | ### 1. DB 작업 6 | 7 | ``` sql 8 | -- 멀티 스키마이기 떄문에 컨테이너 생성 후 다음과 같이 DB 생성 master 노드에서 1회만 하면 복제됨 9 | create database board; 10 | create database user; 11 | ``` 12 | 13 | ```sql 14 | 15 | -- 마지막 실행 쿼리 로그를 확인하기 위해 다음과 같이 설정 실행, 설정값은 replication이 안되므로 각 노드마다 해야함 16 | 17 | SET GLOBAL log_output = 'TABLE'; 18 | SET GLOBAL general_log = 'ON'; 19 | ``` 20 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-separate-ro-rw/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /jpa-separate-ro-rw/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/infra/haproxy/config/haproxy.cfg: -------------------------------------------------------------------------------- 1 | global 2 | log 127.0.0.1 local2 3 | # chroot /var/lib/haproxy # 리눅스 chroot jail 경로 4 | # pidfile /var/run/haproxy.pid # 실행피드명 5 | maxconn 4000 6 | user root 7 | group root 8 | daemon 9 | # tune.ssl.default-dh-param 4000 # ssl 적용시 항목 10 | 11 | defaults 12 | retries 3 13 | timeout queue 1m 14 | timeout connect 10s 15 | timeout client 1m 16 | timeout server 1m 17 | timeout http-keep-alive 10s 18 | timeout check 10s 19 | maxconn 3000 20 | 21 | # GALERA-RW 22 | frontend galera_rw_fe 23 | bind *:3306 24 | default_backend galera_rw_be 25 | 26 | backend galera_rw_be 27 | balance leastconn 28 | server galera_rw galera-node-1-rw:3306 29 | 30 | # GALERA-RO 31 | frontend galera_ro_fe 32 | mode tcp 33 | bind *:3307 34 | default_backend galera-ro-be 35 | 36 | backend galera-ro-be 37 | mode tcp 38 | balance leastconn 39 | server galera-ro-1 galera-node-2-ro:3306 40 | server galera-ro-2 galera-node-3-ro:3306 41 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/infra/mariadb/config/my.cnf: -------------------------------------------------------------------------------- 1 | [galera] 2 | # Mandatory settings 3 | wsrep_on=ON 4 | wsrep_provider=/usr/lib/galera/libgalera_smm.so 5 | wsrep_cluster_address=gcomm://galera-node-1-rw,galera-node-2-ro,galera-node-3-ro 6 | binlog_format=row 7 | default_storage_engine=InnoDB 8 | innodb_autoinc_lock_mode=2 9 | 10 | [mysqld] 11 | character-set-server = utf8 12 | collation-server = utf8_unicode_ci 13 | skip-character-set-client-handshake 14 | innodb_print_all_deadlocks = 1 15 | 16 | # GCache size zero for SST test | default = 128M 17 | wsrep_provider_options="gcache.size=128M;gcache.page_size=128M" -------------------------------------------------------------------------------- /jpa-separate-ro-rw/infra/mariadb/node-1/volume/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-separate-ro-rw/infra/mariadb/node-1/volume/.gitkeep -------------------------------------------------------------------------------- /jpa-separate-ro-rw/infra/mariadb/node-2/volume/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-separate-ro-rw/infra/mariadb/node-2/volume/.gitkeep -------------------------------------------------------------------------------- /jpa-separate-ro-rw/infra/mariadb/node-3/volume/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-separate-ro-rw/infra/mariadb/node-3/volume/.gitkeep -------------------------------------------------------------------------------- /jpa-separate-ro-rw/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'jpa-separate-ro-rw' 2 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/JpaSeparateRoRwApplication.java: -------------------------------------------------------------------------------- 1 | package com.sight; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class JpaSeparateRoRwApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(JpaSeparateRoRwApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/BaseRecordableEntity.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain; 2 | 3 | import org.springframework.data.annotation.CreatedDate; 4 | import org.springframework.data.annotation.LastModifiedDate; 5 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 6 | 7 | import javax.persistence.EntityListeners; 8 | import javax.persistence.MappedSuperclass; 9 | import java.time.LocalDateTime; 10 | 11 | @EntityListeners(AuditingEntityListener.class) 12 | @MappedSuperclass 13 | public abstract class BaseRecordableEntity { 14 | 15 | @CreatedDate 16 | protected LocalDateTime createTime; 17 | 18 | @LastModifiedDate 19 | protected LocalDateTime updateTime; 20 | } -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/board/Board.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.board; 2 | 3 | import com.sight.app.domain.BaseRecordableEntity; 4 | import com.sight.app.domain.board.comment.Comment; 5 | import lombok.AccessLevel; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | import javax.persistence.*; 10 | import java.util.Collections; 11 | import java.util.Set; 12 | 13 | @Entity 14 | @Getter 15 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 16 | public class Board extends BaseRecordableEntity { 17 | 18 | @Id 19 | @GeneratedValue(strategy = GenerationType.IDENTITY) 20 | @Column(name = "board_seq") 21 | private Long boardSeq; 22 | 23 | private String title; 24 | 25 | private String content; 26 | 27 | @Column(name = "serviceuser_seq") 28 | private Long writerSeq; 29 | 30 | @OneToMany 31 | @JoinColumn(name = "comment_seq") 32 | private Set commentList = Collections.emptySet(); 33 | 34 | public Board(String title, String content, Long writerSeq) { 35 | this.title = title; 36 | this.content = content; 37 | this.writerSeq = writerSeq; 38 | } 39 | } -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/board/BoardRepository.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.board; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface BoardRepository extends JpaRepository, BoardRepositoryCustom { 6 | 7 | } 8 | 9 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/board/BoardRepositoryCustom.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.board; 2 | 3 | public interface BoardRepositoryCustom { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/board/BoardRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.board; 2 | 3 | import com.sight.config.db.BaseDataSourceConfig; 4 | import com.sight.config.db.board.BoardDataSourceConfig; 5 | import com.sight.config.db.board.BoardDatabaseConfig; 6 | import com.sight.config.db.board.BoardRouteDataSource; 7 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; 8 | 9 | import javax.persistence.EntityManager; 10 | import javax.persistence.PersistenceContext; 11 | 12 | public class BoardRepositoryImpl extends QuerydslRepositorySupport implements BoardRepositoryCustom { 13 | 14 | public BoardRepositoryImpl() { 15 | super(Board.class); 16 | } 17 | 18 | @Override 19 | @PersistenceContext(unitName = BoardDatabaseConfig.SCHEMA_NAME) 20 | public void setEntityManager(EntityManager entityManager) { 21 | super.setEntityManager(entityManager); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/board/BoardService.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.board; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.springframework.stereotype.Service; 5 | 6 | @Service 7 | @RequiredArgsConstructor 8 | public class BoardService { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/board/comment/Comment.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.board.comment; 2 | 3 | import com.sight.app.domain.BaseRecordableEntity; 4 | import com.sight.app.domain.board.Board; 5 | import lombok.AccessLevel; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | import javax.persistence.*; 10 | 11 | @Entity 12 | @Getter 13 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 14 | public class Comment extends BaseRecordableEntity { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | @Column(name = "comment_seq") 19 | private Long commentSeq; 20 | 21 | @ManyToOne(fetch = FetchType.LAZY) 22 | @JoinColumn(name = "board_seq") 23 | private Board board; 24 | 25 | private String content; 26 | 27 | @Column(name = "serviceuser_seq") 28 | private Long writerSeq; 29 | 30 | public Comment(Board board, String content, Long writerSeq) { 31 | this.board = board; 32 | this.content = content; 33 | this.writerSeq = writerSeq; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/user/MyUser.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.user; 2 | 3 | import com.sight.app.domain.BaseRecordableEntity; 4 | import com.sight.app.web.dto.user.MyUserCreateRequest; 5 | import lombok.AccessLevel; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | import javax.persistence.*; 10 | 11 | @Entity 12 | @Getter 13 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 14 | public class MyUser extends BaseRecordableEntity { 15 | 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | @Column(name = "user_seq") 19 | private Long userSeq; 20 | 21 | private String name; 22 | private String email; 23 | 24 | public MyUser(MyUserCreateRequest request) { 25 | this.name = request.getName(); 26 | this.email = request.getState(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/user/MyUserRepository.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.user; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface MyUserRepository extends JpaRepository, MyUserRepositoryCustom { 6 | 7 | } -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/user/MyUserRepositoryCustom.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.user; 2 | 3 | public interface MyUserRepositoryCustom { 4 | void clearCache(MyUser myUser); 5 | } 6 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/domain/user/MyUserRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.domain.user; 2 | 3 | import com.sight.config.db.BaseDataSourceConfig; 4 | import com.sight.config.db.board.BoardDataSourceConfig; 5 | import com.sight.config.db.user.UserDatabaseConfig; 6 | import org.springframework.data.jpa.repository.Modifying; 7 | import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; 8 | 9 | import javax.persistence.EntityManager; 10 | import javax.persistence.PersistenceContext; 11 | 12 | public class MyUserRepositoryImpl extends QuerydslRepositorySupport implements MyUserRepositoryCustom { 13 | 14 | public MyUserRepositoryImpl() { 15 | super(MyUser.class); 16 | } 17 | 18 | @Override 19 | @PersistenceContext(unitName = UserDatabaseConfig.SCHEMA_NAME) 20 | public void setEntityManager(EntityManager entityManager) { 21 | super.setEntityManager(entityManager); 22 | } 23 | 24 | @Modifying(clearAutomatically = true) 25 | public void clearCache(MyUser myUser) { 26 | getEntityManager().refresh(myUser); 27 | getEntityManager().flush(); 28 | getEntityManager().clear(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/app/web/dto/user/MyUserCreateRequest.java: -------------------------------------------------------------------------------- 1 | package com.sight.app.web.dto.user; 2 | 3 | public class MyUserCreateRequest { 4 | 5 | private String name; 6 | private String state; 7 | 8 | public MyUserCreateRequest() {} 9 | 10 | public MyUserCreateRequest(String name, String state) { 11 | this.name = name; 12 | this.state = state; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public String getState() { 20 | return state; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/config/AppProfile.java: -------------------------------------------------------------------------------- 1 | package com.sight.config; 2 | 3 | public interface AppProfile { 4 | String PROD = "prod"; 5 | String LOCAL = "local"; 6 | String TEST = "test"; 7 | String NON_TEST = "!test"; 8 | } 9 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/config/db/DataSourceRole.java: -------------------------------------------------------------------------------- 1 | package com.sight.config.db; 2 | 3 | public enum DataSourceRole { 4 | READ_WRITE("rw"), // 쓰기 전용 5 | READ_ONLY("ro"), // 읽기 전용 6 | TEST_ONLY("test"); // 테스트 전용 7 | private final String nameSpace; 8 | 9 | DataSourceRole(final String nameSpace) { 10 | this.nameSpace = nameSpace; 11 | } 12 | 13 | public String getNameSpace() { 14 | return nameSpace; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/config/db/DataSourceType.java: -------------------------------------------------------------------------------- 1 | package com.sight.config.db; 2 | 3 | public enum DataSourceType { 4 | 5 | BOARD(BaseDataSourceConfig.BOARD, "app.datasource.board"), 6 | USER(BaseDataSourceConfig.USER, "app.datasource.user"); 7 | 8 | private final String dataSourceSchemaName; 9 | private final String dataSourceProperty; 10 | 11 | DataSourceType(String dataSourceSchemaName, String dataSourceProperty) { 12 | this.dataSourceSchemaName = dataSourceSchemaName; 13 | this.dataSourceProperty = dataSourceProperty; 14 | } 15 | 16 | public String getDataSourceProperty() { 17 | return dataSourceProperty; 18 | } 19 | 20 | public String getDataSourceSchemaName() { 21 | return dataSourceSchemaName; 22 | } 23 | } -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/config/db/board/BoardRouteDataSource.java: -------------------------------------------------------------------------------- 1 | package com.sight.config.db.board; 2 | 3 | import com.sight.config.db.DataSourceRole; 4 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 5 | import org.springframework.transaction.support.TransactionSynchronizationManager; 6 | 7 | import java.util.Map; 8 | 9 | public class BoardRouteDataSource extends AbstractRoutingDataSource { 10 | 11 | public BoardRouteDataSource(Map dataSourceMap) { 12 | super.setTargetDataSources(dataSourceMap); 13 | super.setDefaultTargetDataSource(dataSourceMap.get(DataSourceRole.READ_WRITE)); 14 | } 15 | 16 | @Override 17 | protected Object determineCurrentLookupKey() { 18 | return TransactionSynchronizationManager.isCurrentTransactionReadOnly() 19 | ? DataSourceRole.READ_ONLY : DataSourceRole.READ_WRITE; 20 | } 21 | } -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/config/db/user/UserRouteDataSource.java: -------------------------------------------------------------------------------- 1 | package com.sight.config.db.user; 2 | 3 | import com.sight.config.db.DataSourceRole; 4 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 5 | import org.springframework.transaction.support.TransactionSynchronizationManager; 6 | 7 | import java.util.Map; 8 | 9 | public class UserRouteDataSource extends AbstractRoutingDataSource { 10 | 11 | public UserRouteDataSource(Map dataSourceMap) { 12 | super.setTargetDataSources(dataSourceMap); 13 | super.setDefaultTargetDataSource(dataSourceMap.get(DataSourceRole.READ_WRITE)); 14 | } 15 | 16 | @Override 17 | protected Object determineCurrentLookupKey() { 18 | DataSourceRole dataSourceRole = TransactionSynchronizationManager.isCurrentTransactionReadOnly() 19 | ? DataSourceRole.READ_ONLY : DataSourceRole.READ_WRITE; 20 | 21 | return dataSourceRole; 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/config/jpa/JpaConfig.java: -------------------------------------------------------------------------------- 1 | package com.sight.config.jpa; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 6 | import org.springframework.orm.hibernate5.HibernateExceptionTranslator; 7 | 8 | @Configuration 9 | @EnableJpaAuditing 10 | public class JpaConfig { 11 | 12 | @Bean 13 | public HibernateExceptionTranslator hibernateExceptionTranslator() { 14 | return new HibernateExceptionTranslator(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/java/com/sight/config/queryDsl/QueryDslConfig.java: -------------------------------------------------------------------------------- 1 | package com.sight.config.queryDsl; 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | import javax.persistence.EntityManager; 9 | 10 | @Configuration 11 | public class QueryDslConfig { 12 | 13 | // @Autowired 14 | // private EntityManager entityManager; 15 | // 16 | // @Bean 17 | // public JPAQueryFactory jpaQueryFactory() { 18 | // return new JPAQueryFactory(entityManager); 19 | // } 20 | } 21 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/resources/application-local.properties: -------------------------------------------------------------------------------- 1 | # JPA 2 | spring.jpa.show-sql=true 3 | spring.jpa.database-platform=org.hibernate.dialect.MariaDB103Dialect 4 | spring.jpa.properties.hibernate.format_sql=true 5 | spring.jpa.properties.hibernate.show_sql=true 6 | 7 | # Galera - Board 8 | app.datasource.board.ddl-auto=update 9 | app.datasource.board.driverClassName=org.mariadb.jdbc.Driver 10 | app.datasource.board.username=root 11 | app.datasource.board.password=passwd 12 | 13 | app.datasource.board.rw.jdbc-url=jdbc:mariadb://localhost:3306/board 14 | app.datasource.board.ro.jdbc-url=jdbc:mariadb://localhost:3307/board 15 | 16 | # Galera - User 17 | app.datasource.user.ddl-auto=update 18 | app.datasource.user.driverClassName=org.mariadb.jdbc.Driver 19 | app.datasource.user.username=root 20 | app.datasource.user.password=passwd 21 | 22 | app.datasource.user.rw.jdbc-url=jdbc:mariadb://localhost:3306/user 23 | app.datasource.user.ro.jdbc-url=jdbc:mariadb://localhost:3307/user 24 | 25 | #logging.level.root=debug 26 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | # JPA 2 | spring.jpa.show-sql=true 3 | spring.jpa.database-platform=org.hibernate.dialect.MariaDB103Dialect 4 | spring.jpa.properties.hibernate.format_sql=true 5 | spring.jpa.properties.hibernate.show_sql=true 6 | 7 | # Galera - Board 8 | app.datasource.board.ddl-auto=update 9 | app.datasource.board.driverClassName=org.mariadb.jdbc.Driver 10 | app.datasource.board.username=root 11 | app.datasource.board.password=passwd 12 | 13 | app.datasource.board.test.jdbc-url=jdbc:mariadb://localhost:3309/board 14 | 15 | # Galera - User 16 | app.datasource.user.ddl-auto=update 17 | app.datasource.user.driverClassName=org.mariadb.jdbc.Driver 18 | app.datasource.user.username=root 19 | app.datasource.user.password=passwd 20 | 21 | app.datasource.user.test.jdbc-url=jdbc:mariadb://localhost:3309/user 22 | 23 | spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=local 2 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/test/java/com/sight/domain/book/BookIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.domain.book; 2 | 3 | import com.sight.app.domain.board.Board; 4 | import com.sight.app.domain.board.BoardRepository; 5 | import com.sight.testType.DataJpaRepoTest; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | 9 | import java.util.List; 10 | 11 | public class BookIntegrationTest extends DataJpaRepoTest { 12 | 13 | @Autowired 14 | BoardRepository boardRepository; 15 | 16 | @Test 17 | public void test() { 18 | List all = boardRepository.findAll(); 19 | System.out.println(all); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/test/java/com/sight/testConfig/JpaTestConfig.java: -------------------------------------------------------------------------------- 1 | package com.sight.testConfig; 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.boot.test.context.TestConfiguration; 6 | import org.springframework.context.annotation.Bean; 7 | 8 | import javax.persistence.EntityManager; 9 | 10 | @TestConfiguration 11 | public class JpaTestConfig { 12 | 13 | @Autowired 14 | private EntityManager entityManager; 15 | 16 | @Bean 17 | public JPAQueryFactory jpaQueryFactory() { 18 | return new JPAQueryFactory(entityManager); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/test/java/com/sight/testType/BaseTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.testType; 2 | 3 | import com.sight.config.AppProfile; 4 | import org.springframework.test.context.ActiveProfiles; 5 | 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | 9 | @ActiveProfiles(AppProfile.LOCAL) 10 | public interface BaseTest { 11 | 12 | default String getResourcePath() { 13 | Path resourcePath = Paths.get("src", "test", "resources"); 14 | return resourcePath.toFile().getAbsolutePath(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/test/java/com/sight/testType/DataJpaRepoTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.testType; 2 | 3 | import com.sight.config.db.board.BoardDataSourceConfig; 4 | import com.sight.config.db.board.BoardDatabaseConfig; 5 | import com.sight.testConfig.JpaTestConfig; 6 | import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; 7 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; 8 | import org.springframework.context.annotation.Import; 9 | 10 | import javax.transaction.Transactional; 11 | 12 | @DataJpaTest 13 | @Transactional 14 | @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 15 | @Import(value = { 16 | JpaTestConfig.class, 17 | BoardDatabaseConfig.class, 18 | BoardDataSourceConfig.class 19 | }) 20 | public abstract class DataJpaRepoTest implements BaseTest { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /jpa-separate-ro-rw/src/test/java/com/sight/testType/IntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.sight.testType; 2 | 3 | import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | import org.springframework.transaction.annotation.Transactional; 6 | 7 | //@Transactional 8 | @SpringBootTest 9 | @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 10 | public abstract class IntegrationTest implements BaseTest { } 11 | -------------------------------------------------------------------------------- /jpa-with-recursive/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /jpa-with-recursive/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | maria-db: 4 | container_name: recursive-mariadb 5 | image: mariadb:10.4 6 | volumes: 7 | - ./infra/volumes/mariadb:/data 8 | ports: 9 | - '3306:3306' 10 | environment: 11 | MYSQL_ROOT_PASSWORD: passwd 12 | MYSQL_DATABASE: recursive 13 | command: 14 | ['mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci'] 15 | 16 | # 17 | #'mcr.microsoft.com/mssql/server' 18 | #'store/oracle/database-enterprise:12.2.0.1-slim' 19 | #'mysql:8.0' 20 | #'postgres:13.1' 21 | -------------------------------------------------------------------------------- /jpa-with-recursive/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /jpa-with-recursive/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /jpa-with-recursive/infra/volumes/mariadb/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/infra/volumes/mariadb/.gitkeep -------------------------------------------------------------------------------- /jpa-with-recursive/infra/volumes/mssql/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/infra/volumes/mssql/.gitkeep -------------------------------------------------------------------------------- /jpa-with-recursive/infra/volumes/mysql/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/infra/volumes/mysql/.gitkeep -------------------------------------------------------------------------------- /jpa-with-recursive/infra/volumes/oracle/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/infra/volumes/oracle/.gitkeep -------------------------------------------------------------------------------- /jpa-with-recursive/infra/volumes/postgre/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/infra/volumes/postgre/.gitkeep -------------------------------------------------------------------------------- /jpa-with-recursive/md-asset/1-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/md-asset/1-table.png -------------------------------------------------------------------------------- /jpa-with-recursive/md-asset/2_select_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/md-asset/2_select_output.png -------------------------------------------------------------------------------- /jpa-with-recursive/md-asset/3-criteria.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/md-asset/3-criteria.PNG -------------------------------------------------------------------------------- /jpa-with-recursive/md-asset/4-sqlresult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/md-asset/4-sqlresult.png -------------------------------------------------------------------------------- /jpa-with-recursive/md-asset/5-executionplan.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/jpa-with-recursive/md-asset/5-executionplan.PNG -------------------------------------------------------------------------------- /jpa-with-recursive/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "blog" 2 | -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/kotlin/com/sight/blog/BlogApplication.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication 4 | import org.springframework.boot.runApplication 5 | 6 | @SpringBootApplication 7 | class BlogApplication 8 | 9 | fun main(args: Array) { 10 | runApplication(*args) 11 | } 12 | -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/kotlin/com/sight/blog/app/domain/company/Company.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.app.domain.company 2 | 3 | import com.sight.blog.common.jpa.BaseRecordableEntity 4 | import javax.persistence.* 5 | 6 | @Entity 7 | class Company( 8 | 9 | @Id 10 | @GeneratedValue(strategy = GenerationType.IDENTITY) 11 | @Column(name = "company_seq") 12 | var seq: Long ?= null, 13 | 14 | var name: String, 15 | ): BaseRecordableEntity() -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/kotlin/com/sight/blog/app/domain/company/CompanyRepository.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.app.domain.company 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository 4 | 5 | interface CompanyRepository: JpaRepository -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/kotlin/com/sight/blog/app/domain/department/Department.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.app.domain.department 2 | 3 | import com.sight.blog.app.domain.company.Company 4 | import com.sight.blog.common.jpa.BaseRecordableEntity 5 | import javax.persistence.* 6 | 7 | @Entity 8 | class Department( 9 | 10 | @Id 11 | @GeneratedValue(strategy = GenerationType.IDENTITY) 12 | @Column(name = "dept_seq") 13 | var seq: Long ?= null, 14 | 15 | @ManyToOne(fetch = FetchType.LAZY) 16 | @JoinColumn(name = "parent_dept_seq") 17 | var parent: Department ?= null, 18 | 19 | @ManyToOne(fetch = FetchType.LAZY) 20 | @JoinColumn(name = "company_seq") 21 | var company: Company, 22 | 23 | var depth: Int, 24 | 25 | var name: String, 26 | 27 | ): BaseRecordableEntity() -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/kotlin/com/sight/blog/app/domain/department/DepartmentCTE.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.app.domain.department 2 | 3 | import com.blazebit.persistence.CTE 4 | import com.sight.blog.app.domain.company.Company 5 | import com.sight.blog.common.jpa.BaseRecordableEntity 6 | import javax.persistence.* 7 | 8 | @CTE 9 | @Entity 10 | class DepartmentCTE ( 11 | 12 | @Id 13 | @GeneratedValue(strategy = GenerationType.IDENTITY) 14 | @Column(name = "dept_seq") 15 | var seq: Long ?= null, 16 | 17 | @ManyToOne(fetch = FetchType.LAZY) 18 | @JoinColumn(name = "parent_dept_seq") 19 | var parent: Department ?= null, 20 | 21 | @ManyToOne(fetch = FetchType.LAZY) 22 | @JoinColumn(name = "company_seq") 23 | var company: Company, 24 | 25 | var depth: Int, 26 | 27 | var name: String, 28 | ): BaseRecordableEntity() 29 | -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/kotlin/com/sight/blog/common/jpa/BaseRecordableEntity.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.common.jpa 2 | 3 | import org.springframework.data.annotation.CreatedDate 4 | import org.springframework.data.annotation.LastModifiedDate 5 | import org.springframework.data.jpa.domain.support.AuditingEntityListener 6 | import java.time.LocalDateTime 7 | import javax.persistence.* 8 | 9 | @EntityListeners(AuditingEntityListener::class) 10 | @MappedSuperclass 11 | abstract class BaseRecordableEntity { 12 | 13 | @CreatedDate 14 | lateinit var createdAt: LocalDateTime 15 | 16 | @LastModifiedDate 17 | lateinit var updatedAt: LocalDateTime 18 | } -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/kotlin/com/sight/blog/common/jpa/JpaConfig.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.common.jpa 2 | 3 | import org.springframework.context.annotation.Configuration 4 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing 5 | 6 | @Configuration 7 | @EnableJpaAuditing 8 | class JpaConfig -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/kotlin/com/sight/blog/common/jpa/criteria/CriteriaConfig.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.common.jpa.criteria 2 | 3 | import com.blazebit.persistence.Criteria 4 | import com.blazebit.persistence.CriteriaBuilderFactory 5 | import org.springframework.context.annotation.Bean 6 | import org.springframework.context.annotation.Configuration 7 | import javax.persistence.EntityManager 8 | 9 | @Configuration 10 | class CriteriaConfig( 11 | private val entityManager: EntityManager 12 | ) { 13 | 14 | @Bean 15 | fun createCriteriaBuilderFactory() : CriteriaBuilderFactory { 16 | val config = Criteria.getDefault() 17 | return config.createCriteriaBuilderFactory(entityManager.entityManagerFactory) 18 | } 19 | } -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/kotlin/com/sight/blog/common/jpa/queryDsl/QueryDslConfig.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.common.jpa.queryDsl 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory 4 | import org.springframework.context.annotation.Bean 5 | import org.springframework.context.annotation.Configuration 6 | import javax.persistence.EntityManager 7 | 8 | @Configuration 9 | class QueryDslConfig( 10 | private val entityManager: EntityManager 11 | ) { 12 | @Bean 13 | fun jpaQueryFactory(): JPAQueryFactory { 14 | return JPAQueryFactory(entityManager) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # MySQL 2 | spring.datasource.url=jdbc:mariadb://localhost:3306/recursive 3 | spring.datasource.driverClassName=org.mariadb.jdbc.Driver 4 | spring.datasource.username=root 5 | spring.datasource.password=passwd 6 | 7 | #JPA 8 | #spring.jpa.show-sql=true 9 | spring.jpa.database-platform=org.hibernate.dialect.MariaDB103Dialect 10 | #spring.jpa.properties.hibernate.format_sql=true 11 | spring.jpa.properties.hibernate.show_sql=true 12 | spring.jpa.hibernate.ddl-auto=none 13 | -------------------------------------------------------------------------------- /jpa-with-recursive/src/main/resources/sql/ddl.sql: -------------------------------------------------------------------------------- 1 | create table company 2 | ( 3 | board_seq bigint auto_increment 4 | primary key, 5 | created_at datetime(6) null, 6 | updated_at datetime(6) null, 7 | name varchar(255) null 8 | ); 9 | 10 | create table department 11 | ( 12 | dept_seq bigint auto_increment 13 | primary key, 14 | created_at datetime(6) null, 15 | updated_at datetime(6) null, 16 | depth int not null, 17 | name varchar(255) null, 18 | company_seq bigint null, 19 | parent_dept_seq bigint null, 20 | 21 | constraint FK27x8o5lawxio5jovbp7qdabm4 22 | foreign key (company_seq) references company (board_seq), 23 | 24 | constraint FKgaog9q38ysvmm8rfhgm7qcndy 25 | foreign key (parent_dept_seq) references department (dept_seq) 26 | ); 27 | 28 | -------------------------------------------------------------------------------- /jpa-with-recursive/src/test/kotlin/com/sight/blog/config/TestEnv.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.config 2 | 3 | object TestEnv { 4 | const val TEST = "test" 5 | } -------------------------------------------------------------------------------- /jpa-with-recursive/src/test/kotlin/com/sight/blog/config/jpa/CriteriaConfig.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.config.jpa 2 | 3 | import com.blazebit.persistence.Criteria 4 | import com.blazebit.persistence.CriteriaBuilderFactory 5 | import org.springframework.boot.test.context.TestConfiguration 6 | import org.springframework.context.annotation.Bean 7 | import javax.persistence.EntityManager 8 | 9 | @TestConfiguration 10 | class CriteriaConfig( 11 | private val entityManager: EntityManager 12 | ) { 13 | 14 | @Bean 15 | fun createCriteriaBuilderFactory() : CriteriaBuilderFactory { 16 | val config = Criteria.getDefault() 17 | return config.createCriteriaBuilderFactory(entityManager.entityManagerFactory) 18 | } 19 | } -------------------------------------------------------------------------------- /jpa-with-recursive/src/test/kotlin/com/sight/blog/config/jpa/JpaTestConfig.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.config.jpa 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory 4 | import org.springframework.boot.test.context.TestConfiguration 5 | import org.springframework.context.annotation.Bean 6 | import javax.persistence.EntityManager 7 | 8 | @TestConfiguration 9 | class JpaTestConfig( 10 | private val entityManager: EntityManager 11 | ) { 12 | 13 | @Bean 14 | fun jpaQueryFactory(): JPAQueryFactory = JPAQueryFactory(entityManager) 15 | } -------------------------------------------------------------------------------- /jpa-with-recursive/src/test/kotlin/com/sight/blog/config/test/BaseTest.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.config.test 2 | 3 | import java.nio.file.Path 4 | import java.nio.file.Paths 5 | 6 | interface BaseTest { 7 | 8 | fun getResourcePath(): String { 9 | val resourceDirectory: Path = Paths.get("src", "test", "resources") 10 | return resourceDirectory.toFile().absolutePath 11 | } 12 | } -------------------------------------------------------------------------------- /jpa-with-recursive/src/test/kotlin/com/sight/blog/config/test/DataJpaRepoTest.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.config.test 2 | 3 | import com.sight.blog.common.jpa.criteria.CriteriaConfig 4 | import com.sight.blog.config.TestEnv 5 | import com.sight.blog.config.jpa.JpaTestConfig 6 | import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase 7 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest 8 | import org.springframework.context.annotation.Import 9 | import org.springframework.test.context.ActiveProfiles 10 | import org.springframework.transaction.annotation.Transactional 11 | 12 | @DataJpaTest 13 | @Transactional 14 | @ActiveProfiles(TestEnv.TEST) 15 | @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 16 | @Import(value = [JpaTestConfig::class, CriteriaConfig::class]) 17 | abstract class DataJpaRepoTest: BaseTest -------------------------------------------------------------------------------- /jpa-with-recursive/src/test/kotlin/com/sight/blog/config/test/IntegrationTest.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.config.test 2 | 3 | import com.sight.blog.config.TestEnv 4 | import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase 5 | import org.springframework.boot.test.context.SpringBootTest 6 | import org.springframework.test.context.ActiveProfiles 7 | import org.springframework.transaction.annotation.Transactional 8 | 9 | @SpringBootTest 10 | @ActiveProfiles(TestEnv.TEST) 11 | @Transactional 12 | @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 13 | abstract class IntegrationTest: BaseTest -------------------------------------------------------------------------------- /jpa-with-recursive/src/test/kotlin/com/sight/blog/config/test/IntegrationTestWithNoRollback.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.config.test 2 | 3 | import com.sight.blog.config.TestEnv 4 | import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase 5 | import org.springframework.boot.test.context.SpringBootTest 6 | import org.springframework.test.context.ActiveProfiles 7 | import org.springframework.transaction.annotation.Transactional 8 | 9 | @SpringBootTest 10 | @ActiveProfiles(TestEnv.TEST) 11 | @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) 12 | abstract class IntegrationTestWithNoRollback: BaseTest 13 | 14 | -------------------------------------------------------------------------------- /jpa-with-recursive/src/test/kotlin/com/sight/blog/domain/company/CompanyDataGeneration.kt: -------------------------------------------------------------------------------- 1 | package com.sight.blog.domain.company 2 | 3 | import com.sight.blog.app.domain.company.Company 4 | import com.sight.blog.app.domain.company.CompanyRepository 5 | import com.sight.blog.config.test.IntegrationTestWithNoRollback 6 | import org.junit.jupiter.api.Disabled 7 | import org.junit.jupiter.api.Test 8 | import org.springframework.beans.factory.annotation.Autowired 9 | 10 | class CompanyDataGeneration: IntegrationTestWithNoRollback() { 11 | 12 | @Autowired 13 | lateinit var companyRepository: CompanyRepository 14 | 15 | @Test @Disabled 16 | fun `테스트 회사 데이터 생성`() { 17 | val boardCnt = 2000 18 | 19 | // given 20 | for(boardWriteCnt in 1..boardCnt) { 21 | val board = Company( 22 | name = "회사 $boardCnt", 23 | ) 24 | companyRepository.save(board) 25 | } 26 | 27 | // then 28 | } 29 | } -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### IntelliJ IDEA ### 9 | .idea 10 | *.iws 11 | *.iml 12 | *.ipr 13 | out/ 14 | !**/src/main/**/out/ 15 | !**/src/test/**/out/ 16 | 17 | single-node-mariadb/infra/mariadb/volume 18 | !single-node-mariadb/infra/mariadb/volume/.gitkeep 19 | 20 | galera-cluster/infra/mariadb/master-1/volume 21 | !galera-cluster/infra/mariadb/master-1/volume/.gitkeep 22 | 23 | galera-cluster/infra/mariadb/master-2/volume 24 | !galera-cluster/infra/mariadb/master-2/volume/.gitkeep 25 | 26 | galera-cluster/infra/mariadb/master-3/volume 27 | !galera-cluster/infra/mariadb/master-3/volume/.gitkeep 28 | 29 | redis-cluster/redis-master 30 | !redis-cluster/redis-master/data/.gitkeep 31 | 32 | redis-cluster/redis-slave 33 | !redis-cluster/redis-slave/data/.gitkeep -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/README.md: -------------------------------------------------------------------------------- 1 | ### 프로메테우스 + 그라파나로 메트릭 지표 구성 2 | 3 | 대상 4 | - Mariadb 5 | - Mariadb/Galera Cluster 6 | - Redis Cluster 7 | 8 | redis-cluster의 경우 도커 이미지 별도로 사용 9 | Docker for Window 환경에서 실험했기 때문에 호스트를 ```host.docker.internal```로 잡음 10 | 11 | ``` 12 | docker run -e "IP=0.0.0.0" -p 7000-7005:7000-7005 grokzen/redis-cluster:latest 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/config/my.cnf: -------------------------------------------------------------------------------- 1 | [galera] 2 | # Mandatory settings 3 | wsrep_on=ON 4 | wsrep_provider=/usr/lib/galera/libgalera_smm.so 5 | wsrep_cluster_address=gcomm://galera-master-node-1,galera-master-node-2,galera-master-node-3 6 | binlog_format=row 7 | default_storage_engine=InnoDB 8 | innodb_autoinc_lock_mode=2 9 | 10 | [mysqld] 11 | character-set-server = utf8 12 | collation-server = utf8_unicode_ci 13 | skip-character-set-client-handshake 14 | innodb_print_all_deadlocks = 1 15 | 16 | # GCache size zero for SST test | default = 128M 17 | 18 | wsrep_provider_options="gcache.size=0;gcache.page_size=0" 19 | # wsrep_provider_options="gcache.size=128M;gcache.page_size=128M" -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/master-1/volume/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/master-1/volume/.gitkeep -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/master-2/volume/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/master-2/volume/.gitkeep -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/master-3/volume/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/master-3/volume/.gitkeep -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/sql/ddl.sql: -------------------------------------------------------------------------------- 1 | create table author 2 | ( 3 | id int(7) not null primary key AUTO_INCREMENT, 4 | first_name varchar(50) null, 5 | last_name varchar(50) not null, 6 | date_of_birth date null, 7 | year_of_birth int(7) null, 8 | distinguished int(1) null 9 | ); 10 | 11 | create table book_store 12 | ( 13 | name varchar(400) not null, 14 | constraint name unique (name) 15 | ); 16 | 17 | create table language 18 | ( 19 | id int(7) not null primary key AUTO_INCREMENT, 20 | cd char(2) not null, 21 | description varchar(50) null 22 | ); 23 | 24 | create table book 25 | ( 26 | id int(7) not null primary key AUTO_INCREMENT, 27 | author_id int(7) not null, 28 | title varchar(400) not null, 29 | published_in int(7) not null, 30 | language_id int(7) not null, 31 | ); 32 | 33 | create table book_to_book_store 34 | ( 35 | name varchar(400) not null, 36 | book_id int not null, 37 | stock int null, 38 | primary key (name, book_id), 39 | ); -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/sql/seed.sql: -------------------------------------------------------------------------------- 1 | insert into author (first_name, last_name, date_of_birth, year_of_birth, distinguished) 2 | values ('George', 'Orwell', '1903-06-26', 1903, null), 3 | ('Paulo', 'Coelho', '1947-08-24', 1947, null); 4 | 5 | insert into language (cd, description) 6 | values ('en', 'English'), 7 | ('de', 'Deutsch'), 8 | ('fr', 'Français'), 9 | ('pt', 'Português'); 10 | 11 | insert into book (author_id, title, published_in, language_id) 12 | values (1, '1984', 1948, 1), 13 | (1, 'Animal Farm', 1945, 1), 14 | (2, 'O Alquimista', 1988, 4), 15 | (2, 'Brida', 1990, 2); 16 | 17 | 18 | insert into book_store (name) 19 | values ('Buchhandlung im Volkshaus'), 20 | ('Ex Libris'), 21 | ('Orell Füssli'); 22 | 23 | insert into book_to_book_store (name, book_id, stock) 24 | values ('Buchhandlung im Volkshaus', 3, 1), 25 | ('Ex Libris', 1, 1), 26 | ('Ex Libris', 3, 2), 27 | ('Orell Füssli', 1, 10), 28 | ('Orell Füssli', 2, 10), 29 | ('Orell Füssli', 3, 10); -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/galera-cluster/infra/mariadb/sql/wsrep_status.sql: -------------------------------------------------------------------------------- 1 | show status like 'wsrep%'; 2 | show global status like 'wsrep_cluster_size'; 3 | show global status like 'wsrep_cluster_status'; -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/galera-cluster/infra/prometheus/volume/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/prometheus-mairadb-and-redis/galera-cluster/infra/prometheus/volume/.gitkeep -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/redis-cluster-fail/redis-image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis:6.2.5 2 | 3 | RUN rm -rf /usr/local/bin/docker-entrypoint.sh 4 | ADD redis.conf /usr/local/etc/redis/redis.conf 5 | ADD docker-entrypoint.sh /usr/local/bin 6 | 7 | ## 권한 부여 8 | RUN chmod 755 /usr/local/etc/redis/redis.conf 9 | RUN chmod 755 /usr/local/bin/docker-entrypoint.sh 10 | 11 | ## 소유 변경 12 | RUN chown redis:redis /usr/local/etc/redis/redis.conf 13 | RUN chown redis:redis /usr/local/bin/docker-entrypoint.sh 14 | 15 | EXPOSE $CLIENTPORT 16 | 17 | ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] 18 | CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ] -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/redis-cluster-fail/redis-master/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/prometheus-mairadb-and-redis/redis-cluster-fail/redis-master/data/.gitkeep -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/redis-cluster-fail/redis-slave-1/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/prometheus-mairadb-and-redis/redis-cluster-fail/redis-slave-1/data/.gitkeep -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/redis-cluster-fail/redis-slave-2/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/prometheus-mairadb-and-redis/redis-cluster-fail/redis-slave-2/data/.gitkeep -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/single-node-mariadb/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | promethus: 4 | image: prom/prometheus 5 | volumes: 6 | - ./infra/prometheus:/etc/prometheus 7 | ports: 8 | - '9090:9090' 9 | promethus-mariadb: 10 | image: mariadb:10.4 11 | depends_on: 12 | - 'promethus' 13 | volumes: 14 | - ./infra/mariadb/volume:/var/lib/mysql 15 | - ./infra/mariadb/config:/etc/mysql/mariadb.conf.d 16 | ports: 17 | - '3307:3306' 18 | environment: 19 | MYSQL_ROOT_PASSWORD: passwd 20 | MYSQL_DATABASE: test-db 21 | 22 | promethus-mysql-exporter: 23 | image: prom/mysqld-exporter 24 | depends_on: 25 | - 'promethus-mariadb' 26 | ports: 27 | - '9104:9104' 28 | environment: 29 | DATA_SOURCE_NAME: "root:passwd@(host.docker.internal:3307)/" 30 | 31 | grafana: 32 | image: grafana/grafana 33 | depends_on: 34 | - 'promethus' 35 | ports: 36 | - '3000:3000' -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/single-node-mariadb/infra/mariadb/sql/ddl.sql: -------------------------------------------------------------------------------- 1 | create table author 2 | ( 3 | id int(7) not null primary key AUTO_INCREMENT, 4 | first_name varchar(50) null, 5 | last_name varchar(50) not null, 6 | date_of_birth date null, 7 | year_of_birth int(7) null, 8 | distinguished int(1) null 9 | ); 10 | 11 | create table book_store 12 | ( 13 | name varchar(400) not null, 14 | constraint name unique (name) 15 | ); 16 | 17 | create table language 18 | ( 19 | id int(7) not null primary key AUTO_INCREMENT, 20 | cd char(2) not null, 21 | description varchar(50) null 22 | ); 23 | 24 | create table book 25 | ( 26 | id int(7) not null primary key AUTO_INCREMENT, 27 | author_id int(7) not null, 28 | title varchar(400) not null, 29 | published_in int(7) not null, 30 | language_id int(7) not null 31 | ); 32 | 33 | create table book_to_book_store 34 | ( 35 | name varchar(400) not null, 36 | book_id int not null, 37 | stock int null, 38 | primary key (name, book_id) 39 | ); -------------------------------------------------------------------------------- /prometheus-mairadb-and-redis/single-node-mariadb/infra/mariadb/sql/seed.sql: -------------------------------------------------------------------------------- 1 | insert into author (first_name, last_name, date_of_birth, year_of_birth, distinguished) 2 | values ('George', 'Orwell', '1903-06-26', 1903, null), 3 | ('Paulo', 'Coelho', '1947-08-24', 1947, null); 4 | 5 | insert into language (cd, description) 6 | values ('en', 'English'), 7 | ('de', 'Deutsch'), 8 | ('fr', 'Français'), 9 | ('pt', 'Português'); 10 | 11 | insert into book (author_id, title, published_in, language_id) 12 | values (1, '1984', 1948, 1), 13 | (1, 'Animal Farm', 1945, 1), 14 | (2, 'O Alquimista', 1988, 4), 15 | (2, 'Brida', 1990, 2); 16 | 17 | 18 | insert into book_store (name) 19 | values ('Buchhandlung im Volkshaus'), 20 | ('Ex Libris'), 21 | ('Orell Füssli'); 22 | 23 | insert into book_to_book_store (name, book_id, stock) 24 | values ('Buchhandlung im Volkshaus', 3, 1), 25 | ('Ex Libris', 1, 1), 26 | ('Ex Libris', 3, 2), 27 | ('Orell Füssli', 1, 10), 28 | ('Orell Füssli', 2, 10), 29 | ('Orell Füssli', 3, 10); -------------------------------------------------------------------------------- /reactor-java/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/reactor-java/.DS_Store -------------------------------------------------------------------------------- /reactor-java/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /reactor-java/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | java 3 | } 4 | 5 | group = "org.example" 6 | version = "1.0-SNAPSHOT" 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | implementation("io.projectreactor:reactor-core:3.3.8.RELEASE") 14 | testImplementation("io.projectreactor:reactor-test:3.3.8.RELEASE") 15 | 16 | testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.1") 17 | testImplementation("org.junit-pioneer:junit-pioneer:0.9.0") 18 | testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.3.1") 19 | } 20 | -------------------------------------------------------------------------------- /reactor-java/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SightStudio/blog-code/1a489aa165e67f10096e8dd6578b2ac99b21e861/reactor-java/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /reactor-java/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /reactor-java/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "reactor-java" 2 | 3 | -------------------------------------------------------------------------------- /reactor-java/src/test/java/BackPressureTest.java: -------------------------------------------------------------------------------- 1 | import org.junit.jupiter.api.Test; 2 | import org.reactivestreams.Subscriber; 3 | import org.reactivestreams.Subscription; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class BackPressureTest { 7 | 8 | @Test 9 | public void subscribeTest() { 10 | Flux.range(0, 1000) 11 | .log() 12 | .subscribe(new MySubscriber()); 13 | } 14 | } 15 | 16 | class MySubscriber implements Subscriber { 17 | 18 | private Subscription subscription; 19 | private int requestCnt; 20 | 21 | @Override 22 | public void onSubscribe(Subscription s) { 23 | this.subscription = s; 24 | this.subscription.request(10); 25 | } 26 | 27 | @Override 28 | public void onNext(Object object) { 29 | requestCnt++; 30 | if(requestCnt % 10 == 0) { 31 | this.subscription.request(10); 32 | } 33 | } 34 | 35 | @Override 36 | public void onError(Throwable t) { 37 | 38 | } 39 | 40 | @Override 41 | public void onComplete() { 42 | System.out.println("Subscribe Finished"); 43 | } 44 | } 45 | --------------------------------------------------------------------------------