Skip to content
This repository was archived by the owner on Oct 24, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/main/java/com/flab/makedel/annotation/SetDataSource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.flab.makedel.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SetDataSource {

DataSourceType dataSourceType();

enum DataSourceType {
MASTER, SLAVE;
}

}
27 changes: 27 additions & 0 deletions src/main/java/com/flab/makedel/aop/SetDataSourceAspect.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.flab.makedel.aop;

import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.exception.WrongDataSourceException;
import com.flab.makedel.routingdatasource.RoutingDataSourceManager;
import java.sql.SQLException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SetDataSourceAspect {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이렇게 처리해줄 필요없이 스프링에서 제공하는 기능이 있을 것 같습니다~ readOnly 트랜잭션이면 slave에서 읽는다거나요~

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Transactional을 서비스에 붙히고 readOnly인지 아닌지에 따라 DataSoruce들을 분기해줄 수 있는 방식과 지금처럼 AOP방식을 고민을 했엇습니다.

하지만 트랜잭션 방식을 사용하여 라우팅해준다면 모든 서비스에 @Transactional을 붙혀야 하고 단일연산에도 트랜잭션 설정을 해줘야 해서 AOP방식으로 데이터소스를 나누도록 구현 하였습니다.


@Before("@annotation(com.flab.makedel.annotation.SetDataSource) && @annotation(target)")
public void setDataSource(SetDataSource target) throws WrongDataSourceException {

if (target.dataSourceType() == DataSourceType.MASTER
|| target.dataSourceType() == DataSourceType.SLAVE) {
RoutingDataSourceManager.setCurrentDataSourceName(target.dataSourceType());
} else {
throw new WrongDataSourceException("Wrong DataSource Type : Should Check Exception");
}

Copy link
Collaborator Author

@tjdrnr0557 tjdrnr0557 Dec 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

만약 DataSource Type이 Master나 Slave가 아니라면 개발자들이 어노테이션에 오타를 내거나 이름을 잘못지은 오류일 것입니다.

따라서 아예 컴파일타임에 개발자들이 exception을 알아채고 처리를 해주어야 할 것 같아서 checked Exception인 SQLException을 사용하였습니다.

}
}
86 changes: 86 additions & 0 deletions src/main/java/com/flab/makedel/config/DataSourceConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.flab.makedel.config;

import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.routingdatasource.RoutingDataSourceManager;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;

@Configuration
@PropertySource("classpath:/application-dev.properties")
public class DataSourceConfig {

@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}

@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}

@Bean
public DataSource routingDataSource(
@Qualifier(value = "masterDataSource") DataSource masterDataSource,
@Qualifier(value = "slaveDataSource") DataSource slaveDataSource) {

AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource() {
@Override
protected Object determineCurrentLookupKey() {
DataSourceType dataSourceType = RoutingDataSourceManager.getCurrentDataSourceName();

if (TransactionSynchronizationManager
.isActualTransactionActive()) {
boolean readOnly = TransactionSynchronizationManager
.isCurrentTransactionReadOnly();
if (readOnly) {
dataSourceType = DataSourceType.SLAVE;
} else {
dataSourceType = DataSourceType.MASTER;
}
}

RoutingDataSourceManager.removeCurrentDataSourceName();
return dataSourceType;
}
};

Map<Object, Object> targetDataSources = new HashMap<>();

targetDataSources.put(DataSourceType.MASTER, masterDataSource);
targetDataSources.put(DataSourceType.SLAVE, slaveDataSource);

routingDataSource.setTargetDataSources(targetDataSources);
routingDataSource.setDefaultTargetDataSource(masterDataSource);

return routingDataSource;
}

@Bean
public DataSource lazyRoutingDataSource(
@Qualifier(value = "routingDataSource") DataSource routingDataSource) {
return new LazyConnectionDataSourceProxy(routingDataSource);
}

@Bean
public PlatformTransactionManager transactionManager(
@Qualifier(value = "lazyRoutingDataSource") DataSource lazyRoutingDataSource) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(lazyRoutingDataSource);
return transactionManager;
}
}
7 changes: 5 additions & 2 deletions src/main/java/com/flab/makedel/config/DatabaseConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -33,9 +34,11 @@ public class DatabaseConfig {
private final ApplicationContext applicationContext;

@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
public SqlSessionFactory sqlSessionFactory(
@Qualifier(value = "lazyRoutingDataSource") DataSource lazyRoutingDataSource)
throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setDataSource(lazyRoutingDataSource);
sqlSessionFactoryBean.setMapperLocations(
applicationContext.getResources("classpath:/mapper/**/*.xml"));
return sqlSessionFactoryBean.getObject();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.flab.makedel.Exception;
package com.flab.makedel.exception;

public class DuplicatedIdException extends RuntimeException {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.flab.makedel.Exception;
package com.flab.makedel.exception;

public class NotExistIdException extends RuntimeException {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.flab.makedel.exception;

import java.sql.SQLException;

public class WrongDataSourceException extends SQLException {

public WrongDataSourceException(String message) {
super(message);
}
}
5 changes: 5 additions & 0 deletions src/main/java/com/flab/makedel/mapper/MenuMapper.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package com.flab.makedel.mapper;

import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.dto.MenuDTO;
import java.util.List;

public interface MenuMapper {

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void insertMenu(MenuDTO menu);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void deleteMenu(long menuId);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
List<MenuDTO> selectStoreMenu(long storeId);

}
5 changes: 5 additions & 0 deletions src/main/java/com/flab/makedel/mapper/OptionMapper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.flab.makedel.mapper;

import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.dto.OptionDTO;
import java.util.List;

Expand All @@ -15,10 +17,13 @@

public interface OptionMapper {

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void insertOptionList(List<OptionDTO> optionList);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void deleteOptionList(List<OptionDTO> optionList);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
List<OptionDTO> selectOptionList(long menuId);

}
9 changes: 9 additions & 0 deletions src/main/java/com/flab/makedel/mapper/OrderMapper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.flab.makedel.mapper;

import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.dto.OrderDTO;
import com.flab.makedel.dto.OrderDTO.OrderStatus;
import com.flab.makedel.dto.OrderDetailDTO;
Expand All @@ -9,18 +11,25 @@

public interface OrderMapper {

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void insertOrder(OrderDTO orderDTO);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void completeOrder(long totalPrice, long orderId, OrderStatus orderStatus);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
OrderReceiptDTO selectOrderReceipt(long orderId);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
List<OrderStoreDetailDTO> selectDetailStoreOrder(long storeId);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void approveOrder(long orderId, OrderStatus orderStatus);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void updateStandbyOrderToDelivering(long orderId, String riderId, OrderStatus orderStatus);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void finishDeliveringOrder(long orderId, OrderStatus orderStatus);

}
3 changes: 3 additions & 0 deletions src/main/java/com/flab/makedel/mapper/OrderMenuMapper.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.flab.makedel.mapper;

import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.dto.OrderMenuDTO;
import java.util.List;

public interface OrderMenuMapper {

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void insertOrderMenu(List<OrderMenuDTO> orderMenuList);

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.flab.makedel.mapper;

import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.dto.OrderMenuOptionDTO;
import java.util.List;

public interface OrderMenuOptionMapper {

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void insertOrderMenuOption(List<OrderMenuOptionDTO> orderMenuOptionList);

}
3 changes: 3 additions & 0 deletions src/main/java/com/flab/makedel/mapper/PayMapper.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.flab.makedel.mapper;

import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.dto.PayDTO;

public interface PayMapper {

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void insertPay(PayDTO payDTO);

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.flab.makedel.mapper;

import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.dto.StoreCategoryDTO;
import java.util.List;

Expand All @@ -11,6 +13,7 @@

public interface StoreCategoryMapper {

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
List<StoreCategoryDTO> selectCategoryList();

}
9 changes: 9 additions & 0 deletions src/main/java/com/flab/makedel/mapper/StoreMapper.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package com.flab.makedel.mapper;

import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.dto.StoreInfoDTO;
import com.flab.makedel.dto.StoreDTO;
import java.util.List;

public interface StoreMapper {

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void insertStore(StoreDTO store);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
List<StoreDTO> selectStoreList(String ownerId);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
boolean isMyStore(long storeId, String ownerId);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
StoreDTO selectStore(long storeId, String ownerId);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void closeMyStore(long storeId);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void openMyStore(long storeId);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
StoreInfoDTO selectStoreInfo(long storeId);

}
8 changes: 8 additions & 0 deletions src/main/java/com/flab/makedel/mapper/UserMapper.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
package com.flab.makedel.mapper;

import com.flab.makedel.annotation.LoginCheck.UserLevel;
import com.flab.makedel.annotation.SetDataSource;
import com.flab.makedel.annotation.SetDataSource.DataSourceType;
import com.flab.makedel.dto.UserDTO;
import com.flab.makedel.dto.UserInfoDTO;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
boolean isExistsId(String id);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
UserInfoDTO selectUserInfo(String id);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void insertUser(UserDTO user);

@SetDataSource(dataSourceType = DataSourceType.SLAVE)
UserDTO selectUserById(String id);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void deleteUser(String id);

@SetDataSource(dataSourceType = DataSourceType.MASTER)
void updateUserPassword(String id, String newPassword);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.flab.makedel.routingdatasource;

import com.flab.makedel.annotation.SetDataSource.DataSourceType;

public class RoutingDataSourceManager {

private static final ThreadLocal<DataSourceType> currentDataSourceName = new ThreadLocal<>();

public static void setCurrentDataSourceName(DataSourceType dataSourceType) {
currentDataSourceName.set(dataSourceType);
}

public static DataSourceType getCurrentDataSourceName() {
return currentDataSourceName.get();
}

public static void removeCurrentDataSourceName() {
currentDataSourceName.remove();
}
}
Loading