Разработка мобильного словаря с использованием JDBC. Часть 4
(Николай Зайкин)
4. Загрузка и проверка таблиц словарей в БД.
Для создания нового класса FilesLoader используем элементы предыдущий
двух классов: FilesTester и GetConnection.
Чтобы не создавать новый класс с нуля, воспользуемся старым классом
FilesTester и скопируем его с переименованием:
- Установите курсор на класс
FilesTester. Нажмите правую кнопку мыши
Reorganize -> Copy... Либо через меню Selected ->
Reorganize -> Copy...
- Выберите имя нового класса (
FilesLoader):

Сразу же исправьте в методе main строку создания экземпляра класса
на:
new FilesLoader(dirName);
Основные изменения будут проводиться в конструкторе FilesLoader().
Для введения соответствия между именами файлов словарей на жестком диске и именами
таблиц в базе данных, создадим объект типа java.util.Properties:
Properties tableProps = new Properties();
tableProps.setProperty("abbrev.dict", "abbrev");
tableProps.setProperty("computer.dict", "computer");
tableProps.setProperty("economy.dict", "economy");
tableProps.setProperty("general.dict", "general");
tableProps.setProperty("pc-user.dict", "pc_user");
tableProps.setProperty("public.dict", "public");
tableProps.setProperty("rus-eng.dict", "rus_eng");
tableProps.setProperty("update.dict", "update_d");
Не забудьте добавить строчку:
import java.util.*;
в начало класса FilesLoader(), иначе VisualAge for Java не сможет выполнить
инкрементное компилирование класса после нажатия Ctrl+S.
Аналогично импортируйте в класс пакет java.sql.*.
Так как файлы словарей у нас содержат русские символы в кодировке CP1251, нам следует
сообщить это базе данных. Это выполняется на этапе установки соединения с БД с помощью
нового синтаксиса, который мы еще не рассматривали:
static String DBUrl = "jdbc:mysql://localhost/mdictdb";
....
Properties connInfo = new Properties();
connInfo.put("user", "root");
connInfo.put("password", "rootpassword");
connInfo.put("useUnicode", "true");
connInfo.put("characterEncoding", "Cp1251");
Connection c = DriverManager.getConnection(DBUrl, connInfo);
Для занесения данных в БД используется SQL запрос типа
INSERT INTO table_name(word, translation)
VALUES (value1, value2);
Для ускорения работы программы и экономии ресурсов (памяти) применим класс
PreparedStatement. В отличие от Statement, он предварительно
обрабатывается СУБД или JDBC драйвером, что позволяет сэкономить время на трансляцию
запроса и хранится в прекомпилированном виде, мы только задаем новые параметры новыми
переменным (value1, value2) и вызываем запуск запроса.
Этот тип выражения обычно используется для многократных подобных SQL запросов, имеющих
незначительные отличия (во входных параметрах). Например, при загрузке данных.
Входные параметры обозначаются с помощью вопросительного знака. И перед выполнением
запроса их значения должны быть установлены методами setXXXX().
В Java синтаксисе это схематично выглядит так:
Connection c =
DriverManager.getConnection(DBUrl, connInfo);
PreparedStatement prepStmt = null;
....
prepStmt = c.prepareStatement(
"INSERT INTO " + tableProps.getProperty(s[i])
+ "(word,translation) VALUES (?, ?)");
....
prepStmt.setString(1, word);
prepStmt.setString(2, current);
prepStmt.execute();
Обратите внимание, что отсчет номеров столбцов в методах setXXXX()
начинается с единицы, а не с нуля.
Полный листинг класса FilesLoader приведен ниже, скопируйте из него
недостающие методы в ваш IDE и попробуйте запустить на выполнение.
package mdict.jdbc;
import java.util.*;
import java.sql.*;
import java.io.*;
/**
* This class loads data from flat text files into MySQL tables.
* Creation date: (15.11.01 17:38:58)
* @author: Mikalai Zaikin (NZaikin@iba.by, MZaikin@de.ibm.com)
*/
public class FilesLoader implements FilenameFilter {
static String DBUrl = "jdbc:mysql://localhost/mdictdb";
/**
* This method loads data from flat text files into MySQL tables.
* Creation date: (16.11.01 9:20:09)
*/
public FilesLoader(String dirName) {
Properties tableProps = new Properties();
tableProps.setProperty("abbrev.dict", "abbrev");
tableProps.setProperty("computer.dict", "computer");
tableProps.setProperty("economy.dict", "economy");
tableProps.setProperty("general.dict", "general");
tableProps.setProperty("pc-user.dict", "pc_user");
tableProps.setProperty("public.dict", "public");
tableProps.setProperty("rus-eng.dict", "rus_eng");
tableProps.setProperty("update.dict", "update_d");
File d = new File(dirName);
String s[] = d.list(this);
if (s == null) {
System.out.println("Incorrect directory name '" + dirName + "'.");
System.exit(0);
}
if (s.length == 0) {
System.out.println("Directory '" + dirName + "' is empty.");
System.exit(0);
}
FileReader fileInStream;
BufferedReader dataInStream;
String result = "";
boolean isWord = true;
boolean firstLine = true;
int maxLength = 0;
String current = "";
String word = "";
try {
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
System.out.println("JDBC driver loaded !");
Properties connInfo = new Properties();
connInfo.put("user", "root");
connInfo.put("password", "rootpassword");
connInfo.put("useUnicode", "true");
connInfo.put("characterEncoding", "Cp1251");
Connection c = DriverManager.getConnection(DBUrl, connInfo);
PreparedStatement prepStmt = null;
for (int i = 0; i < s.length; i++) {
prepStmt =
c.prepareStatement(
"INSERT INTO " + tableProps.getProperty(s[i])
+ "(word,translation) VALUES (?, ?)");
try {
fileInStream = new FileReader(dirName
+ File.separator + s[i]);
dataInStream = new BufferedReader(fileInStream);
while ((result = dataInStream.readLine()) != null) {
isWord = (result.trim().length() == 0);
if (isWord) {
prepStmt.setString(1, word);
prepStmt.setString(2, current);
prepStmt.execute();
current = "";
// first line will be a word
firstLine = true;
} else {
// check for word (first line)
// we don't need to count word length,
// only translation length
if (firstLine) {
firstLine = false;
word = result.trim();
// get word into variable
} else {
// add rarriage return characters,
// because readLine() method trim them
current += result + "\r\n";
}
}
}
fileInStream.close();
dataInStream.close();
System.out.println("Table '" +
tableProps.getProperty(s[i]) + "' filled.");
} catch (Throwable exc) {
exc.printStackTrace(System.out);
}
}
System.out.println("Done.");
c.close(); // close DB connection
} catch (Exception ex) {
ex.printStackTrace(System.out);
}
}
/**
* This method perform verification of file name.
* It returns true if the file has dictionary extension (.dict),
* otherwise it returns false.
* This method is required because class FilesLoader implements
* FilenameFilter interface.
* Creation date: (15.11.01 18:12:50)
* @return boolean
* @param fil java.io.File
* @param name java.lang.String
*/
public boolean accept(File dir, String name) {
if (name.endsWith("dict") && (new File(dir, name)).isFile()) {
return true;
}
return false;
}
/**
* Starts the application.
* @param args an array of command-line arguments
*/
public static void main(java.lang.String[] args) {
String dirName = ".";
if (args.length > 0) {
dirName = args[0];
}
new FilesLoader(dirName);
}
}
Попробуйте запустить новый класс на выполнение. Если вы получите исключительную
ситуацию типа "Класс org.gjt.mm.mysql.Driver не найден", это означает, что
VisualAge не может найти класс JDBC драйвера.
Дело в том, что VisualAge for Java использует свой встроенный IBM JDK, и не оспользует
системную переменную окружения %CLASSPATH%. Для прописывания класса драйвера в переменную
CLASSPATH VisualAge for Java сделайте следующее:
- Нажмите мышкой на класс
FilesLoader.
- Выберите в меню Selected -> Run -> Check Class Path (это же
можно сделть через контекстное меню по правой кнопке мышки).
- В Extra directories path поставьте птичку и пропишите в текстовом
поле путь к jar-архиву драйвера (mm.mysql-2.0.7-bin.jar):

Запустите снова класс на выполнение.
Таблицы должны заполниться данными (вы сможете узнать об этом по мере вывода
сообщений):
Для проверки правильности занесенных данных напишем простейший класс
DataTester (этот класс надо запускать именно из VisualAge for Java, так как
Windows консоль использует кодировку MS-DOS - CP866, и при запуске тестовго класса не из
графического приложения вы получите на экране неразбериху, хотя на самом деле, данные
буду храниться и выбираться в правильной кодировке):
package mdict.jdbc;
import java.sql.*;
import java.util.*;
public class DataTester {
static String DBUrl = "jdbc:mysql://localhost/mdictdb";
public static void main(String[] Args) {
try {
Class.forName("org.gjt.mm.mysql.Driver").newInstance();
System.out.println("Driver loaded !");
try {
Properties connInfo = new Properties();
connInfo.put("user", "root");
connInfo.put("password", "rootpassword");
connInfo.put("useUnicode", "true");
connInfo.put("characterEncoding", "Cp1251");
Connection c = DriverManager.getConnection(DBUrl, connInfo);
System.out.println("Connection Created !");
Statement s = c.createStatement();
ResultSet rs = s.executeQuery(
"SELECT * FROM abbrev WHERE word LIKE 'l%';");
while (rs.next()) {
System.out.println("--------------------------------");
System.out.println(rs.getString(1));
System.out.println(rs.getString(2));
}
c.close();
} catch (SQLException e) {
System.out.println("SQLException: " + e.getMessage());
System.out.println("SQLState: " + e.getSQLState());
System.out.println("VendorError: " + e.getErrorCode());
}
} catch (Exception e1) {
System.err.println("Unable to load driver.");
e1.printStackTrace();
}
}
}
Перед запуском не забудьте также добавить в CLASSPATH VisualAge for Java архив с JDBC
драйвером.
Вывод программы должен показать следующий результат.
Если вывод вашей программы совдает, то вы можете переходить к следующему этапу -
написанию графического клиентского приложения.
Если в процессе загрузки данных у вас произошел сбой, вы сможете быстро очистить все
таблицы, скопировав нижеприведенный код:
USE mdictdb;
DELETE FROM abbrev;
DELETE FROM computer;
DELETE FROM economy;
DELETE FROM general;
DELETE FROM pc_user;
DELETE FROM public;
DELETE FROM rus_eng;
DELETE FROM update_d;
в текстовый файл (назовите его, например clear.sql), и запустив файл на
выполнение командой:
mysql> \. clear.sql
TOC | Часть 5

|