Статьи

Практикуя код, Java и базы данных


Время от времени я включаю музыку, выключаю отвлечения, такие как электронная почта и телефон, и перерабатываю некоторые базовые программы. Вещи, которые я знаю, и я сделал несколько раз. Цель состоит в том, чтобы попрактиковаться, вернуться к основам и получить новое понимание. Позже я прочитал о
CodeKata и понял, что то, что я делал, было не совсем неслыханным. Для тех, кто относится к созданию
программного обеспечения как к ремеслу , я могу смело рекомендовать эту практику.

Здесь я хочу поговорить об использовании Java для подключения к базе данных. Элементарно, говорите вы. Абсолютно, я согласен. Я настоятельно рекомендую ссылки 
Соединение с базой данных Oracle
Закрытие соединений с базой данных в Java для ясного, краткого чтения, на случай, если вы хотите получить эти ответы. Однако, если вас интересует более подробное практическое путешествие по этой теме, я предлагаю вам продолжить.

Инструменты 

Oracle. Я работал с различными приложениями, основанными на RDBMS и / или NoSql (
link ), и не имею широкого мнения за / против любого из них. Тем не менее, я склонен выбирать Oracle (
экспресс-издание ) даже для своей среды разработки. Называйте меня старомодным, но пока я не могу войти на «сервер базы данных» и выполнить запросы, чтобы подтвердить, что то, что я «думаю», делало мое приложение в базе данных, я не чувствую уверенности в своем коде.

Maven + Eclipse. Я бы предпочел согласиться со всеми, кто говорит, что Maven — это избыточное решение для простых приложений (до 10 классов). Но опять же, это моя интуиция. Я не чувствую уверенности, если не буду использовать инструменты, которые я буду использовать в любом приложении корпоративного уровня в моих кодекатах (из-за отсутствия лучшего названия). В конце концов, когда вы практикуете свои навыки, если вы не используете надлежащий набор инструментов, практические занятия немного бессмысленны, не так ли?

Разогрев


Как я уже говорил, я использую Maven. У меня есть пакетный файл с основными командами Maven (
подробнее об этом ), который я использую для создания любого нового Java-приложения, а затем импортирую его в Eclipse. Минус всего шума, вот так выглядит командный файл.

Файл: \ MavenCommands.bat

REM =============================
REM Set the env. variables. 
REM =============================
SET PATH=%PATH%;C:\ProgramFiles\apache-maven-3.0.4\bin;
SET JAVA_HOME=C:\ProgramFiles\Java\jdk1.7.0

REM =============================
REM Standalone java application. 
REM =============================
call mvn archetype:generate ^
    -DarchetypeArtifactId=maven-archetype-quickstart ^
    -DinteractiveMode=false ^
    -DgroupId=foo.bar ^
    -DartifactId=javadb001

Это создает полное Java-приложение с фиктивным классом, тестовым набором и т. Д. Файл pom содержит большинство деталей. Я склонен добавлять несколько стандартных элементов в файл pom, прежде чем пытаться что-либо еще. В этом случае я также добавлю тонкий клиент Oracle.

Файл: \ javadb001 \ pom.xml

<properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


<dependencies>

 <!-- Unit test. -->
 <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.10</version>
  <scope>test</scope>
 </dependency>

 <!-- Logging -->
 <dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.0.7</version>
 </dependency>

 <!-- Oracle database driver. -->
 <dependency>
  <groupId>ojdbc</groupId>
  <artifactId>ojdbc</artifactId>
  <version>14</version>
 </dependency>

</dependencies>

<build>

 <!-- Compile and run with current Java version -->
 <plugins>
  <plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>2.5.1</version>
   <configuration>
    <source>1.6</source>
    <target>1.6</target>
   </configuration>
  </plugin>
 </plugins>
</build>

Если вы запустите эту «mvn -e clean install», это должно загрузить все зависимости и скомпилироваться просто.

Код (наконец) 


В этом случае я думаю, что тестовый пример JUnit будет работать просто отлично. Нам просто нужно создать экземпляр драйвера (для подключения к Oracle), предоставить ему некоторые стандартные данные, выполнить попытку подключения, а затем выполнить попытку отключения.

Файл: /javadb001/src/test/java/foo/bar/database/TestConnection.java

public class TestConnection {
 private final static Logger logger = LoggerFactory
   .getLogger(TestConnection.class);

 @Test
 public void test() {

  Connection connection = null;
  try {
   // Load the JDBC driver
   String driverName = "oracle.jdbc.driver.OracleDriver";
   Class.forName(driverName);

   // Create a connection to the database
   String serverName = "127.0.0.1";
   String portNumber = "1521";
   String sid = "XE";
   String url = "jdbc:oracle:thin:@" + serverName + ":" + portNumber
     + ":" + sid;
   String username = "funngames";
   String password = "funngames";
   connection = DriverManager.getConnection(url, username, password);
   assertNotNull(connection);
   logger.debug("All well");

  } catch (ClassNotFoundException e) {
   logger.debug(e.getMessage());
  } catch (SQLException e) {
   logger.debug(e.getMessage());
  } finally {
   if (connection != null) {
    try {
     connection.close();
    } catch (SQLException e) {
     logger.debug(e.getMessage());
     fail("The connection could not be closed.");
    }
   }
  }
 }
}

Вы заметите, что, хотя это самый базовый (и бесполезный по функциональности) фрагмент кода, он довольно хорошо себя ведет. Он перехватывает требуемые исключения и пытается закрыть соединение. Что, возможно, не так легко увидеть, это то, что этот код также хорошо работает в сценариях корпоративных приложений. Он использует стандартный и надежный механизм регистрации, т. Е. Logback. Он использует стандартную сборку, релиз (и многое другое) инструмент, то есть Maven.

Короче говоря, если бы вы могли подумать о некой виртуальной полке, куда ваши инженеры-программисты могли бы подойти и выбрать стандартные шаблоны кода, это один из них. Непрактично в его нынешнем виде, но я надеюсь, что вы поняли концепцию.

Для тех, кто все еще со мной (кстати, поздравляю) и интересуюсь концепцией кодеката, о которой я говорил в начале статьи, есть еще немного.

Можем ли мы снять шаблонный код?


Я люблю Java, потому что это стабильность и прочее. Но, будучи ленивым человеком, я ненавижу писать код, который «кажется» мог бы обрабатываться самим языком. В этом текущем коде множество try-catches является бельмом на глазу. Я понимаю, почему они мне нужны, но это не обязательно означает, что я люблю их писать. Возможно, вы уже догадались, что я имею в виду
лучшее управление ресурсами,   представленное
Project Coin .

В двух словах, Java 7 обещает обработать закрытие ресурсов, то есть Connection в этом случае, само по себе. Давайте попробуем.

Нам нужно сообщить maven, что мы хотим использовать jdk 7.

Файл: /javadb001/pom.xml

<!-- Compile and run with current Java version -->
<plugins>
 <plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>2.5.1</version>
  <configuration>
   <source>1.7</source>
   <target>1.7</target>
  </configuration>
 </plugin>
</plugins>

И нам нужно обновить наш тестовый пример, чтобы создать Connection в попытке позволить java закрыть его самостоятельно.

public void test() throws SQLException {
 String driverName; 

 try {
  // Load the JDBC driver
  driverName = "oracle.jdbc.driver.OracleDriver";
  Class.forName(driverName);
 } catch (ClassNotFoundException e) {
  logger.debug(e.getMessage());
  e.printStackTrace();
 }
 // Create a connection to the database
 String serverName = "127.0.0.1";
 String portNumber = "1521";
 String sid = "XE";
 String url = "jdbc:oracle:thin:@" + serverName + ":" + portNumber
   + ":" + sid;
 String username = "funngames";
 String password = "funngames";
 try(Connection connection = DriverManager.getConnection(url, username, password)){
  assertNotNull(connection);
  logger.debug("Connection made.");   
 }    
}

Если вы сравните этот фрагмент кода с предыдущим, мы избавились как минимум от трех блоков try-catch. Но этот код бесполезен в практическом сценарии, говорите вы. Полностью согласен. Как я упоминал ранее, цель состоит в том, чтобы практиковать написание кода — что-то обыденное — но несколькими способами (надеюсь, новыми способами) и учиться на практике. Целью является не производство готовых, многоразовых компонентов. Качество кода, мастерство важно в этом контексте. Преимущество будет в том, что касается более опытных инженеров в организации и связанных с этим преимуществ для бизнеса.

Наконец мой лакмусовый тест … 


это якобы хороший, высококачественный код, насколько он хорош, когда мы запускаем его 10 000 раз в 5 потоках. Я ненавижу сообщать вам новости, но это не слишком хорошо. Вылетает после 20 — 25 казней. Зачем? И как это исправить? Я обсудил проблему и решение в
stackoverflow . Надеюсь, вам будет интересно.

Re-factor

Эта статья становится длиннее, и я должен завершить сейчас. Давайте переформулируем этот код в положение, когда вещи больше не находятся в модульных тестах. Код должен быть в некоторых классах, где они могут быть использованы клиентским кодом. Как выглядит обновленный тестовый код?

Файл: /javadb001/src/test/java/foo/bar/database/TestConnection.java

 
@Test
@PerfTest(invocations = 100, threads = 1)
@Required(max = 1200, average = 1000)
public void testConnectionFactoryAndUtil(){
 Connection connection = ConnectionFactory.getConnection(); 
 assertNotNull(connection); 
 Util.closeConnection(connection);  
}

Сравните это с более ранним тестом. Это было 24 строки. Предполагая, что вы уверены, что этот тест выглядит лучше, как нам провести рефакторинг, чтобы это произошло? Это действительно ваш звонок, и вы можете сделать это несколькими способами. Вот мой дубль.

Файл: /javadb001/src/main/java/foo/bar/database/ConnectionFactory.java

public class ConnectionFactory {
 private final static Logger logger = LoggerFactory
   .getLogger(ConnectionFactory.class);

 public static Connection getConnection() {
  return getConnection("oracle.jdbc.driver.OracleDriver", "127.0.0.1",
    "1521", "XE", "funngames", "funngames");
 }

 public static Connection getConnection(String driver, String host,
   String port, String sid, String user, String pass) {
  Connection connection = null;
  try {
   // Load the JDBC driver
   Class.forName(driver);
   String url = "jdbc:oracle:thin:@" + host + ":" + port + ":" + sid;
   connection = DriverManager.getConnection(url, user, pass);
   logger.info("Connection opened [{}]", connection.toString()); 
  } catch (ClassNotFoundException e) {
   logger.debug(e.getMessage());
   e.printStackTrace();
  } catch (SQLException e) {
   logger.debug(e.getMessage());
   e.printStackTrace();
  }
  return connection;
 }
} 

Файл: /javadb001/src/main/java/foo/bar/database/Util.java

public class Util {
 private final static Logger logger = LoggerFactory.getLogger(Util.class);

 public static void closeConnection(Connection connection){
  if (connection != null) {
   try {
    logger.info("Attempting connection close [{}]", connection.toString()); 
    connection.close();
    Thread.sleep(500); 
    logger.info("Connection succesfuly closed."); 
   } catch (SQLException e) {    
    logger.debug(e.getMessage());
    e.printStackTrace();
   } catch (InterruptedException e){
    logger.debug(e.getMessage());
    e.printStackTrace();
   }
  }
 }
}

Излишне говорить, что любой из этого кода вряд ли является новым или новаторским. Возможно, вы захотите проверить
этот класс для более полного набора служебных функций для закрытия соединения и связанных ресурсов. Не стесняйтесь использовать эту утилиту (это от Apache) или свернуть свою собственную.