====== JDBC ====== * [[http://javarevisited.blogspot.kr/2012/08/top-10-jdbc-best-practices-for-java.html|Top 10 JDBC Best Practices for Java]] * [[http://www3.ntu.edu.sg/home/ehchua/programming/java/JDBC_Basic.html|An Introductin to Java Database Programming (JDBC) by Examples]] * [[http://docs.oracle.com/javase/tutorial/jdbc/index.html|Trail: JDBC(TM) Database Access (The Java™ Tutorials)]] * [[http://www.onjava.com/pub/a/onjava/2006/08/02/jjdbc-4-enhancements-in-java-se-6.html|JDBC 4.0 Enhancements in Java SE 6]] * [[http://www.javacodegeeks.com/2015/02/jdbc-tutorial.html|JDBC Tutorial - The ULTIMATE Guide]] * [[http://www.java2s.com/Tutorials/Java/JDBC/index.htm|Java2s JDBC Tutorial]] ===== Timeout ===== * DB 연결 설정에서 Timeout은 매우 중요한 부분임. 모두 설정하고 의미 숙지 * [[http://d2.naver.com/helloworld/1321|JDBC Internal - 타임아웃의 이해]] * connection timeout * socket timeout * statement timeout(query timeout) * 각 Connection Pool에서 커넥션을 가져오는 최대 대기시간 설정도 꼭 해준다. connection timeout보다 약간 더 길게 하면 될까? ===== 편리 라이브러리 ===== * [[java:jinq|Jinq]] * [[java:jooq|jOOQ]] * [[java:jdbi|JDBI]] * [[springframework:jdbc|Springframework JDBC]] * [[java:fluent_jdbc|Fluent JDBC]] * [[java:jdbc:datasource_proxy|DataSource Proxy]] ===== SQL Logging ===== * 대부분의 JDBC Driver는 자체적으로 logging 기능을 끄고 켤 수 있는 경우가 많다. * [[http://zer0.free.fr/craftsman/spy.php|Craftsman Spy 1.0.5]] : SQL 구문, 실행 시간등을 일괄적으로 로그로 남길 수 있다. * [[http://java.dzone.com/articles/logging-spring-jdbc-and|Logging with Spring JDBC and Craftsman Spy]] * [[http://www.javabeat.net/2012/06/new-features-jdbc-3-0/|New Features of JDBC 3.0]] * [[https://github.com/p6spy/p6spy|P6Spy]] * [[https://code.google.com/p/log4jdbc-log4j2/|Log4jdbc-log4j2]] : JDBC 로깅 with log4j2 and slf4j * [[https://vladmihalcea.com/2016/05/03/the-best-way-of-logging-jdbc-statements/|The best way of logging JDBC statements]] * [[java:jdbc:datasource_proxy|DataSource Proxy]] ===== Db 접속 테스트. 가장 기본 JDBC 접속 및 쿼리 ===== public class DbTester { public static void main(String[] args) throws Exception { if (args.length != 4) { System.err.println("Usage: java -cp [dbjdbcdriver.jar]:. DbTester [jdbcurl] [db-username] [db-password] [sql]"); } String jdbcUrl = args[0]; String username = args[1]; String password = args[2]; String sql = args[3]; testDb(jdbcUrl, username, password, sql); } public static void testDb(String jdbcUrl, String username, String password, String sql) throws SQLException { Connection con = null; Statement statement = null; try { System.out.println(">> Processing JDBC URL : "+ jdbcUrl); Class.forName(“driverClassFQCN”); // no need in Java 6/JDBC 4 con = DriverManager.getConnection(jdbcUrl, username, password); statement = con.createStatement(); boolean executed = statement.execute(sql); System.out.println(String.format("Executed '%s' result - %s", sql, executed)); } finally { if (statement != null) { con.close(); // 사실은 try/catch로 묶어야함. } if (con != null) { con.close(); // 여기도 try/catch로 묶어야함. } } } } * Java 6, JDBC 4.0 부터는 ''Class.forName()''이 불필요하다. [[https://www.mkyong.com/jdbc/jdbc-class-forname-is-no-longer-required/|JDBC Class.forName() is no longer required – Mkyong.com]] ===== JDBC Driver ===== * [[http://docs.oracle.com/javase/6/docs/api/java/sql/DriverManager.html#getDriver%28java.lang.String%29|DriverManager.getDriver(jdbcUrl)]]은 각 JDBC Driver 객체의 [[http://docs.oracle.com/javase/6/docs/api/java/sql/Driver.html#acceptsURL%28java.lang.String%29|Driver.acceptsURL(url)]]을 호출하여 해당 JDBC URL을 처리할 수 있는 Driver를 골라 커넥션을 맺도록 한다. * 이 때문에 동일 JDBC URL을 사용하는 두 개 이상의 JDBC 드라이버를 등록할 수 없다. * 해결책은 조금 변현된 URL을 받아들이도록 처리한 새로운 Driver를 만들고 이를 기존 드라이버에 위임하면 된다.(acceptsURL Override 필요). * 새로운 드라이버 클래스를 만들 때 주의할 점. * ''static {}'' 영역에 드라이버 클래스 등록 코드 필요 static { try { DriverManager.registerDriver(new MyNewDriver()); } catch (SQLException ex) { throw new RuntimeException("Can't register driver!"); } } * 기존 이 중 등록된 기존 드라이버를 [[http://docs.oracle.com/javase/6/docs/api/java/sql/DriverManager.html#deregisterDriver%28java.sql.Driver%29|DriverManager.deregister(Driver 객체)]]해줘야 한다. 기존 드라이버 객체는 [[http://docs.oracle.com/javase/6/docs/api/java/sql/DriverManager.html#getDrivers%28%29|DriverManager.getDrivers()]]로 확보할 수 있다. ===== HA-JDBC ===== * [[http://ha-jdbc.github.io/|HA-JDBC]] 어느 JDBC 드라이버에서나 사용할 수 있는 클러스터링 DB JDBC Driver ===== Connection.setClientInfo ===== * JDBC 4(Java 6 이후)를 지원하는 JDBC 드라이버의 경우 지원한다. * [[http://docs.oracle.com/javase/7/docs/api/java/sql/Connection.html#setClientInfo%28java.lang.String,%20java.lang.String%29|Connection.setClientInfo()]]를 통해 값을 설정하면 JDBC 드라이버가 이를 자기만의 방법으로 DB 서버로 전송한다. * [[database:mysql:jdbc|MySQL JDBC]]의 경우 기본적으로는 주석(Comment)로 달아주는 등의 역할을 한다. * [[java:database:bonecp|BoneCP]]의 경우 ''BoneCPDataSource.setClientInfo(properties)''로 설정하면 자동으로 ''Connection.setClientInfo''를 매번 호출하여 지정된 모든 프라퍼티를 세팅해준다. * 기본 프라퍼티 * ''ApplicationName'' - The name of the application currently utilizing the connection * ''ClientUser'' - The name of the user that the application using the connection is performing work for. This may not be the same as the user name that was used in establishing the connection. * ''ClientHostname'' - The hostname of the computer the application using the connection is running on. * 예제 코드 : BoneCPDataSource dataSource = new BoneCPDataSource(); dataSource.setDriverClass(com.mysql.jdbc.Driver.class.getCanonicalName()); dataSource.setUser("root"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF8"); dataSource.setLogStatementsEnabled(true); Properties clientInfo = new Properties(); clientInfo.setProperty("ApplicationName", "This is JDBC TEST"); InetAddress addr = InetAddress.getLocalHost(); clientInfo.setProperty("ClientHostname", addr.getHostName()); clientInfo.setProperty("ClientHostaddress", addr.getHostAddress()); dataSource.setClientInfo(clientInfo); Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement(); statement.executeQuery("select * from xxx /* hello world! */"); statement.close(); dataSource.close(); * 서버의 Query Log에 남은 결과 : /* ApplicationName=This is JDBC TEST, ClientHostname=kwon37xi-dev, ClientHostaddress=127.0.1.1 */ select * from xxx /* hello world! */ ===== JDBC 4 DriverManager ===== * JDBC 4의 [[https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html|DriverManager]]는 기존처럼 ''Class.forName("driverClassFQCN")'' 처리 과정이 없어도 자동으로 JDBC Driver를 등록해주는 기능이 있다. * JDBC Driver가 JDBC 4를 구현하고 jar 파일 안에 ''META-INF/services/java.sql.Driver''파일이 존재하고 그 안에 Driver Class FQCN이 기입돼 있어야 한다. * 이는 [[https://docs.oracle.com/javase/8/docs/api/java/sql/DriverManager.html|DriverManager]]와 각 JDBC Driver 클래스들의 Class Loader가 일치할 때만 작동하는 것 같다. When the method getConnection is called, the DriverManager will attempt to locate a suitable driver from amongst those loaded at initialization and those loaded explicitly using the same classloader as the current applet or application. * 따라서 Tomcat에 웹 애플리케이션으로 올리거나 할 때는 ''WEB-INF/lib''에 JDBC 드라이버가 있으면 JDBC 드라이버 자동로딩 기능은 작동하지 않는 것으로 보인다. * ''${CATALINA_HOME}/lib''에 두어야 올바로 작동하는 듯 하다. ===== 특정 Table 의 meta data 얻기 ===== try (Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3307/dbname", "username", "password")) { final DatabaseMetaData metaData = con.getMetaData(); final ResultSet rs = metaData.getTables(null, null, "[tableName]", new String[] { "TABLE" }); while(rs.next()) { final ResultSetMetaData rsMetaData = rs.getMetaData(); final int columnCount = rsMetaData.getColumnCount(); for (int i = 1; i <= columnCount; i++) { System.out.println("column " + i + ", column name: " + rsMetaData.getColumnName(i) + " , value: " + rs.getString(i))); } } } ===== SQL 생성 ===== * [[https://github.com/OpenGamma/ElSql|ElSql]] ===== 참고 ===== * [[http://examples.javacodegeeks.com/core-java/sql/jdbc-databasemetadata-example/|JDBC DatabaseMetaData Example]] * [[http://openhms.sourceforge.net/sqlbuilder/|Builder style classes for creating SQL queries]] * [[https://examples.javacodegeeks.com/core-java/sql/jdbc-resultsetextractor-example/|JDBC ResultSetExtractor Example | Examples Java Code Geeks - 2017]] * [[http://www.baeldung.com/jdbc-batch-processing|Batch Processing in JDBC]] * [[https://www.javaworld.com/article/3388036/what-is-jdbc-introduction-to-java-database-connectivity.html|What is JDBC? Introduction to Java Database Connectivity | JavaWorld]]