EJB(xml/mail/jms/jdbc)
2018.09.28 / 01:10

JDBC·Î ½ÇÇàµÇ´Â SQL¿¡ ÀÚµ¿À¸·Î ÇÁ·ÎÁ§Æ® Á¤º¸ ÁÖ¼® ³²±â±â

GAScripter
Ãßõ ¼ö 207

ÀÌ ±ÛÀº Java±â¹Ý¿¡¼­ JDBC¿Í À̸¦ ±â¹ÝÀ¸·Î ÇÑ Persistence Framework¸¦ ÀÌ¿ëÇØ SQLÀ» ½ÇÇàÇÒ ¼ö ÀÖ´Â °³¹ßÀÚ¸¦ ´ë»óÀ¸·Î ¸ðµç JDBC¸¦ ÅëÇØ ½ÇÇàµÇ´Â SQL ±¸¹®¿¡ ¾ÖÇø®ÄÉÀÌ¼Ç Á¤º¸¸¦ ÁÖ¼®À¸·Î ³Ö´Â ¹ýÀ» ¼³¸íÇÕ´Ï´Ù.

¿Ö SQL Äõ¸®¿¡ ÇÁ·ÎÁ§Æ® À̸§À» ³²±â°í ½Í³ª?

º¸Åë Monolithic ¾ÆÅ°ÅØó·Î ÇÁ·ÎÁ§Æ®¸¦ ÁøÇàÇÏ°Ô µÇ¸é ¸ðµç µ¥ÀÌÅ͸¦ ÇϳªÀÇ µ¥ÀÌÅͺ£À̽º¿¡ ´Ù ³Ö´Â ¹æ½ÄÀ¸·Î °³¹ßÀ» ÇÏ°Ô µË´Ï´Ù. ¼­ºñ½º°¡ °è¼Ó MonolithicÀ¸·Î À¯Áö °¡´ÉÇÑ ¼öÁØÀ̶ó¸é »ó°ü¾øÁö¸¸ ¿î ÁÁ°Ôµµ Æø¹ßÀûÀ¸·Î ¼ºÀåÇÏ¿© ¹öÆ¿ ¼ö ¾ø°Ô µÇ¸é ¸¶ÀÌÅ©·Î¼­ºñ½º ¾ÆÅ°ÅØó·Î Çϳª¾¿ ºÐ¸®¸¦ ÇÏ°Ô µË´Ï´Ù.

À̶§ ÇÑ ¹ø¿¡ ¸ðµç µ¥ÀÌÅͺ£À̽º¸¦ °¢°¢ÀÇ ¸¶ÀÌÅ©·Î¼­ºñ½º¿¡¼­ ÇÑ ¹ø¿¡ ³ª´²¼­ °¡Á®°¡¸é ÁÁ°ÚÁö¸¸ °øÅë µ¥ÀÌÅͺ£À̽º¿¡¼­ ¿ÏÀüÈ÷ ¹þ¾î³ª±â¿¡´Â »ó´çÈ÷ ¿À·£ ½Ã°£ÀÌ °É¸³´Ï´Ù.

ÀÌ ±ä °íÅëÀÇ ½Ã°£ µ¿¾È¿¡ ¸Å¿ì ¸¹Àº ¹®Á¦°¡ ¹ß»ýÇÏ°Ô µË´Ï´Ù.

¿©·¯ ÇÁ·ÎÁ§Æ®¿¡¼­ ÇϳªÀÇ °øÅë DB¿¡ Äõ¸®¸¦ ³¯¸®´Ù º¸´Ï ¾î´À ÆÀÀÇ ´©±º°¡°¡ À妽º ¾È Ÿ´Â Äõ¸®¸¦ À߸ø Â¥°Å³ª ȤÀº ´ë±Ô¸ðÀÇ µ¥ÀÌÅ͸¦ ÀоîµéÀÌ´Â Batch ¼º ÀÛ¾÷À» ¼öÇàÇßÀ» ¶§ °øÅë DB´Â CPU 100%¸¦ Ä¡°Ô µÇ°í °í°´µéÀº ÇÏ¿°¾øÀÌ ±â´Ù·Á¾ß ÇÏ´Â ÀÏÀÌ ¸Å¿ì ÀÚÁÖ ¹ß»ýÇÏ°Ô µË´Ï´Ù.

À̶§ ºü¸£°Ô ¾î¶² ÇÁ·ÎÁ§Æ®ÀÇ Äõ¸®°¡ ¹®Á¦¸¦ ÀÏÀ¸Ä×´ÂÁö ã¾Æ³»¸é ÁÁ½À´Ï´Ù¸¸, ÀÌ°Ô ±×¸® ½±Áö°¡ ¾Ê½À´Ï´Ù. IP ÁÖ¼Ò°¡ ÀÖ´õ¶óµµ ±× IPÀÇ ¼­¹ö¿¡ °¡¼­ ¾î´À ÆÀÀÇ ¹«½¼ ÇÁ·ÎÁ§Æ® ¼­¹öÀÎÁö¸¦ È®ÀÎÇÏ´Â µîÀÇ º¹Àâµµ°¡ Ãß°¡µË´Ï´Ù.

±×·¡¼­ ¸ðµç SQLÀÇ ¸Ç ¾Õ¿¡ ¾î´À ÆÀÀÇ ¹«½¼ ÇÁ·ÎÁ§Æ®¿¡¼­ ¿Â ¿äûÀÎÁö¸¦ ÁÖ¼®À¸·Î ³²°ÜµÎ¸é ´À¸° Äõ¸® ·Î±×¸¦ º¸ÀÚ¸¶ÀÚ Á¶±ÝÀÌ¶óµµ ºü¸£°Ô ÇØ´ç ÆÀÀ» ã¾Æ°¡ ¹®Á¦¸¦ ÇØ°áÇÒ ¼ö ÀÖÁö ¾ÊÀ»±î¿ä?

»ç½Ç ÀÌ¿¡ °üÇÑ ±ÛÀ» ¸î ³â Àü¿¡ ¾´ ÀûÀÌ ÀÖ½À´Ï´Ù. JDBC SQL ±¸¹®¿¡ Ŭ¶óÀ̾ðÆ® Á¤º¸ ³²±â±â ÇÏÁö¸¸ ÀÌ ±ÛÀº Hibernate ±×¸®°í MySQL JDBC µå¶óÀ̹ö¿¡ ±¹ÇÑÇÑ ±â¹ýÀ̾ú½À´Ï´Ù.

¹è´ÞÀÇ ¹ÎÁ·Àº ÃÖ¼Ò µÎ °¡Áö ÀÌ»óÀÇ µ¥ÀÌÅͺ£À̽º¸¦ »ç¿ëÇϸç Persistence Frameworkµµ HibernatejOOQQueryDSLMyBatis, Spring JDBCTemplate µî ´Ù¾çÇÏ°Ô »ç¿ë ÁßÀÔ´Ï´Ù.

µû¶ó¼­ Á» ´õ º¸ÆíÀûÀÎ ÇØ°áÃ¥ÀÌ ÇÊ¿äÇÕ´Ï´Ù.

±¸ÇöÀÇ ±âº» ¾ÆÀ̵ð¾î

JavaÀÇ µ¥ÀÌÅͺ£À̽º Á¢¼Ó°ú ½ÇÇà¿¡ °üÇÑ APIµé(JDBC)Àº DataSourceConnectionStatementPreparedStatement µîÀÇ ÀÎÅÍÆäÀ̽º·Î Àß Ãß»óÈ­µÅ ÀÖ½À´Ï´Ù.

½ÇÇàµÇ´Â SQL ±¸¹®ÀÌ °áÁ¤µÇ´Â ¼ø°£Àº Connection.prepareStatement("SQL ±¸¹®") À̶§°Å³ª, ȤÀº Statement.execute("SQL ±¸¹®")Statement.executeQuery("SQL ±¸¹®")Statement.executeUpdate("SQL ±¸¹®") ÀÌ Á¤µµÀÔ´Ï´Ù(»ç½Ç ´õ ÀÖÁö¸¸¡¦).

JavaÀÇ ¸ðµç Connection PoolÀº DataSource ÀÎÅÍÆäÀ̽º¸¦ ±¸ÇöÇÏ°í ÀÖ½À´Ï´Ù.

¿©±â¼­ °£´ÜÇÑ ¾ÆÀ̵ð¾î°¡ µµÃâµË´Ï´Ù.

  • DataSourceProxy & ConnectionProxy
    • Connection Pool DataSource¸¦ °¨½Î´Â DataSourceProxy ¸¦ ¸¸µé°í, ¾ÖÇø®ÄÉÀ̼ǿ¡´Â DataSourceProxy¸¦ ³ëÃâÇÕ´Ï´Ù.
    • ¿©±â¼­ getConnection()ÀÌ È£ÃâµÇ¸é ½ÇÁ¦ µ¥ÀÌÅͼҽº°¡ ¸®ÅÏÇØÁØ Connection °´Ã¼¸¦ °¨½Î°í ÀÖ´ÂConnectionProxy °´Ã¼¸¦ ¸®ÅÏÇØÁÝ´Ï´Ù.
  • PreparedStatement
    • ConnectionProxy.prepareStatement("SQL ±¸¹®") È£ÃâÀÌ ÀϾ¸é ½ÇÁ¦·Î´Â SQL¿¡ ¾ÖÇø®ÄÉÀÌ¼Ç Á¤º¸¸¦ Ãß°¡ÇÑ Connection.prepareStatement("/* ÇÁ·ÎÁ§Æ® Á¤º¸ ÁÖ¼® */ SQL ±¸¹®") À» È£ÃâÇÏ°í ±× °á°ú¸¦ ¹ÝȯÇÕ´Ï´Ù.
    • ÀÌ·¸°Ô µÇ¸é ±× °á°ú·Î ³ª¿Â PreparedStatement °´Ã¼´Â DB¿¡ ÇÁ·ÎÁ§Æ® Á¤º¸ ÁÖ¼®ÀÌ µé¾î°¡ ÀÖ´Â SQLÀ» Àü¼ÛÇÏ°Ô µË´Ï´Ù.
  • Statement
    • ConnectionProxy.createStatement() È£ÃâÀÌ ÀϾ´Ù¸é ½ÇÁ¦ Statement °´Ã¼¸¦ °¨½Î´Â StatementProxy °´Ã¼¸¦ ¸®ÅÏÇØÁÝ´Ï´Ù.
    • ÀÌÈÄ StatementProxy.execute/executeQuery/executeUpdate("SQL ±¸¹®") ÀÌ È£ÃâµÇ¸é ½ÇÁ¦·Î´Â Statement.execute/executeQuery/executeUpdate("/* ÇÁ·ÎÁ§Æ® Á¤º¸ ÁÖ¼® */ SQL ±¸¹®") À» È£ÃâÇÕ´Ï´Ù.
    • ÀÌ·¸°Ô µÇ¸é Statement °´Ã¼´Â DB¿¡ ÇÁ·ÎÁ§Æ® Á¤º¸ ÁÖ¼®ÀÌ µé¾î°¡ ÀÖ´Â SQLÀ» Àü¼ÛÇÏ°Ô µË´Ï´Ù.

óÀ½ºÎÅÍ ¸ðµç Proxy¸¦ Á÷Á¢ ±¸ÇöÇصµ »ó°üÀº ¾ø°ÚÀ¸³ª Á» ´õ ½±°Ô °¡´Â ¹æ¹ýÀ» ã¾Æº¸¾Ò½À´Ï´Ù.

Tomcat JDBC Connection Pool

Tomcat JDBC Connection PoolÀº Tomcat°ú ÇÔ²² °³¹ßµÇ°í ÀÖ´Â Ä¿³Ø¼Ç Ç®·Î HikariCP¿Í ÇÔ²² ¿äÁò °¡Àå ¸¹ÀÌ »ç¿ëµÇ¸ç(SpringBoot 1.xÀÇ ±âº» Ä¿³Ø¼Ç Ç®) ¼º´Éµµ ÁؼöÇÑ ÆíÀÔ´Ï´Ù.

ÀÌ Connection Pool¿¡´Â JDBC Interceptor¶ó´Â °³³äÀÌ ÀÖ½À´Ï´Ù. Ä¿³Ø¼ÇÇ®¿¡¼­ ÀÚüÀûÀ¸·Î DataSourceProxy¿Í ConnectionProxy¸¦ Á¦°øÇØÁÖ°í SQL ½ÇÇàÀ» °¡·Îä¼­ slow query ·Î±×¸¦ ³²±â´Â µîÀÇ ÀÏÀ» ÇÒ ¼ö ÀÖ½À´Ï´Ù.

¹®¼­¸¦ º¸¸é ±âº»ÀûÀ¸·Î À¯¿ëÇÑ Interceptor µéÀ» ¸î °¡Áö Á¦°øÇØÁÖ°í ÀÖ½À´Ï´Ù.

Àú´Â ÀÏÀ» °£´ÜÈ÷ ³¡³»°íÀÚ Tomcat JDBC Connection PoolÀ» »ç¿ëÇÏ°í SQL ±¸¹®À» °¡·Îä¾î ¼³Á¤ÇÑ ÇÁ·ÎÁ§Æ® À̸§À» ÁÖ¼®À¸·Î ¸Ç ¾Õ¿¡ ³Ö¾îÁÖ´Â JDBC Interceptor ¸¦ ¸¸µé¾ú½À´Ï´Ù.

ÇØ´ç ¼Ò½ºÄÚµå´Â woowabros/tomcat-jdbc-pool-sql-caller-info-comment¶ó´Â github ÀúÀå¼Ò¿¡ °ø°³ÇØ µÎ¾ú½À´Ï´Ù.

½ÇÁ¦ ÄÚµå´Â ÆÄÀÏ ÇÑ °³À̹ǷΠ»ç¿ëÇÏ½Ç ºÐµéÀº SqlCallerInfoCommentInterceptor.java ÆÄÀÏÀ» º¹»çÇÏ¿© ÀÚ½ÅÀÇ ÇÁ·ÎÁ§Æ®¿¡ ³Ö°í Tomcat JDBC Connection PoolÀ» ¸¸µé¾îÁÖ½Ã¸é µË´Ï´Ù.

Spring Boot¿¡¼­ YML·Î ¼³Á¤ÇÑ´Ù¸é ´ÙÀ½°ú °°°Ú³×¿ä. baemin_in_woowabros ´ë½Å ÀÚ½ÅÀÌ ³Ö°í ½ÍÀº Á¤º¸¸¦ ³Ö½À´Ï´Ù.

spring:
  datasource:
    url: .....
    type: org.apache.tomcat.jdbc.pool.DataSource
    tomcat:
      ....
      jdbc-interceptors: in.woowa.tomcat.jdbc.pool.interceptor.SqlCallerInfoCommentInterceptor(projectName=baemin_in_woowabros)

ȤÀº Java Code·Î Á÷Á¢ ¼³Á¤ÇÑ´Ù¸é

import org.apache.tomcat.jdbc.pool.DataSource;

DataSource dataSource = new DataSource();
//... ±âŸ ¼³Á¤
dataSource.setJdbcInterceptors("in.woowa.tomcat.jdbc.pool.interceptor.SqlCallerInfoCommentInterceptor(projectName=baemin_in_woowabros)");

À§¿Í °°ÀÌ ¼³Á¤ÇÏ¸é ¸ðµç SQL ±¸¹®Àº ¸Ç ¾Õ¿¡ /* baemin_in_woowabros */ SELECT .... ÇüÅ·ΠÁÖ¼®ÀÌ ºÙÀº »óÅ·ΠÀü¼ÛµË´Ï´Ù.

Ȥ½Ã³ª ¸ô¶ó SQL Injection¿¡ ´ëºñÇÏ¿© ¿µ¹®ÀÚ/¼ýÀÚ/¹ØÁÙ µî¸¸ °¡´ÉÇÏ°Ô ÇÏ¿´½À´Ï´Ù. ÇÏÁö¸¸ ÀÌ ºÎºÐÀº ¿øÇÏ´Â ´ë·Î Äڵ带 º¯°æÇؼ­ ÇѱÛÀ» ³Ö°Ô Çϼŵµ ¹«¹æÇÕ´Ï´Ù.

°£´ÜÇÑ ÄÚµå ¼³¸í

tomcat connection poolÀÇ JDBC Interceptor´Â org.apache.tomcat.jdbc.pool.JdbcInterceptor¸¦ »ó¼ÓÇؼ­ ±¸ÇöÇØ¾ß ÇÕ´Ï´Ù¸¸, ¶Ç ±ÍÂúÀ¸¹Ç·Î ÃÖ´ëÇÑ ¸¹ÀÌ ±¸ÇöµÈ ±âº» ±¸ÇöüÀΠorg.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor¸¦ »ó¼ÓÇÏ¿´½À´Ï´Ù.

StatementDecoratorInterceptor´Â ±âº»ÀûÀ¸·Î DataSource Proxy¿Í Connection Proxy±îÁö´Â µÅ Àֱ⠶§¹®¿¡ Connection.prepareStatement ¸Þ¼­µå¿Í ÀÏ¹Ý Statement »ý¼º½Ã SqlChangeStatementProxy¶ó´Â °´Ã¼¸¦ »ý¼ºÇØÁÖ°í ±× ¾È¿¡¼­ Statement.execute µî...ÀÌ È£ÃâµÉ ¶§ SQLÀ» °¡·Îä¾î ¹Ù²ãÄ¡±âÇÏ°Ô ÇÏ¿´½À´Ï´Ù.

¸¶¹«¸®

ÁÖ¼®À¸·Î ÇÁ·ÎÁ§Æ®¸¦ ³Ö´Â ¹æ¹ýÀº »ç¿ë¹ýÀÌ ³Ê¹«³ª °£´ÜÇÏÁö¸¸, ½ÇÁ¦·Î ¹®Á¦°¡ ¹ß»ýÇßÀ» ¶§ »ó´çÇÑ µµ¿òÀ» ÁÙ °ÍÀ¸·Î »ý°¢µË´Ï´Ù.

¿©·¯ ¾ÖÇø®ÄÉÀ̼ÇÀÌ »ç¿ëÇÏ´Â °øÅë DB°¡ ÀÖ´Ù¸é Java¸¦ »ç¿ëÇÏÁö ¾Ê´Â ÇÁ·ÎÁ§Æ®¶óµµ ÀÌ·± ±â´ÉÀ» ¸¸µé¸é ÁÁÀ» °Í °°°í, ±×°Ô ¾È µÇ´õ¶óµµ Á÷Á¢ ÁÖ¼®À¸·Î DBA°¡ ¾Ë¾Æº¸°í ¹Ù·Î ¿¬¶ôÇÒ ¼ö ÀÖ´Â Á¤µµÀÇ ÁÖ¼®À» SQL ¾Õ´Ü¿¡ ³²°ÜÁÖ´Â ½À°üÀ» Áö´Ï´Â °ÍÀÌ ÁÁÀ» °Í °°½À´Ï´Ù.

±ÍÂúÀº ÀÏÀ» ÁÙÀÌ·Á°í Tomcat JDBC Connection PoolÀÇ JdbcInterceptor¸¦ »ç¿ëÇÏ°Ô Çß´õ´Ï ¼³Á¤Àº Âü ½±Áö¸¸, Äڵ带 ÀÌÇØÇÏ´Â °ÍÀº ¿ÀÈ÷·Á ´õ ¾î·Á¿öÁø °Í °°½À´Ï´Ù. ¾îµð±îÁö°¡ JdbcInterceptor°¡ ÇØÁÖ´Â °ÍÀÌ°í ¾îµðºÎÅÍ°¡ Á÷Á¢ ±¸ÇöÇÑ °ÍÀÎÁö °æ°è°¡ ¸íÈ®È÷ ¾È µå·¯³ª º¸¿©¼­ µÎ Äڵ带 ´Ù ÀÌÇØÇؾ߸¸ ÇÏ°Ô µÇ¾ú½À´Ï´Ù. Àúµµ ¸·»ó ±ÛÀ» ¾²·Á°í Äڵ带 ´Ù½Ã º¸´Ù º¸´Ï ¸Å¿ì Çò°¥¸³´Ï´Ù.

DataSource ºÎÅÍ ¸ðµÎ Á÷Á¢ Proxy¸¦ ¸¸µé¾îº¸´Â °Íµµ ÁÁÀº °øºÎ°¡ µÉ °Í °°°í, ¿ÀÈ÷·Á Äڵ尡 ´õ °£°áÇØÁú °Í °°½À´Ï´Ù. ¶ÇÇÑ Æ¯Á¤ Connection Pool¿¡ ÀÇÁ¸ÇÏÁöµµ ¾Ê°í¿ä.