Две отличные статьи касательно оптимизации запросов через OR в MySQL: раз, два.
Latest
Deadlock в приложениях на Java
Во время работы игрового сервера, несколько раз было замечено возникновение deadlock’ов. Обнаружить причину их возникновения пока непосильная задача, поэтому дабы избежать вытекающих отсюда проблем – делается рестарт сервака.
Решение простое, так как в стандартной поставке JDK есть нужный нам класс: ThreadMXBean, который можно получить путем вызова: ManagementFactory.getThreadMXBean().
Реализация:
import java.lang.management.*; import java.util.logging.Logger; public class DeadLockDetector implements Runnable { private static final Logger log = Logger.getLogger(DeadLockDetector.class.getName()); private static DeadLockDetector instance; private final ThreadMXBean tmx; public static DeadLockDetector getInstance() { return instance; } private DeadLockDetector() { tmx = ManagementFactory.getThreadMXBean(); instance = this; } public final void run() { boolean deadlock = false; while (!deadlock) { try { long[] ids = tmx.findDeadlockedThreads(); // Deadlock detected if (ids != null) { deadlock = true; ThreadInfo[] tis = tmx.getThreadInfo(ids, true, true); String info = "DeadLock Found!\n"; for (ThreadInfo ti : tis) { info += ti.toString(); } for (ThreadInfo ti : tis) { LockInfo[] locks = ti.getLockedSynchronizers(); MonitorInfo[] monitors = ti.getLockedMonitors(); if (locks.length == 0 && monitors.length == 0) { // This thread isn't a reason, it's just blocked by external deadlock continue; } ThreadInfo dl = ti; info += "Java-level deadlock:\n"; info += "\t" + dl.getThreadName() + " is waiting to lock " + dl.getLockInfo().toString() + " which is held by " + dl.getLockOwnerName() + "\n"; while ((dl = tmx.getThreadInfo(new long[]{dl.getLockOwnerId()}, true, true)[0]).getThreadId() != ti.getThreadId()) { info += "\t" + dl.getThreadName() + " is waiting to lock " + dl.getLockInfo().toString() + " which is held by " + dl.getLockOwnerName() + "\n"; } } // listenerEngine.methodInvoked(DeadlockListener.class); log.severe(info); log.severe("Shutting down server with exit code = 2, startup script will do authomatic restart."); System.exit(2); } Thread.sleep(200); } catch (Exception e) { log.severe(e.getLocalizedMessage()); } } } public static void start() { Thread t = new Thread(new DeadLockDetector()); t.setName("DeadLock Monitor"); t.setDaemon(true); t.setPriority(Thread.MAX_PRIORITY); t.start(); log.info("DeadLock Detector started."); } }
Сжатие *.mp3 файлов с помощью Lame
Скачиваем последнюю версию Lame. Далее для автоматизации процесса используем Java (увы скриптовые языки я не знаю).
import java.io.File; import java.io.FilenameFilter; import java.io.IOException; /** * User: Babanin * Date: 04.09.2010 * Time: 14:36:04 */ public class LameQuality { private static final String DIR_TO_CONVERT = "C:\\fileToConvert"; private static final String LAME_FILE_DIR = "C:\\lame\\"; private static final String LAME_FILENAME = "lame.exe"; private static final String LAME_OPTIONS = "-V9"; private static final String PREFIX = "converted_"; public static void main(String[] args) { File baseDir = new File(DIR_TO_CONVERT); if (baseDir.isDirectory()) { File[] files = baseDir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { return name.endsWith(".mp3"); } }); for (File inputFile : files) { try { String inputFilePath = inputFile.getAbsolutePath(); File outputFile = new File(inputFilePath.substring(0, inputFilePath.lastIndexOf("\\") + 1) + PREFIX + inputFilePath.substring(inputFilePath.lastIndexOf("\\") + 1)); if (outputFile.exists()) { //noinspection ResultOfMethodCallIgnored outputFile.delete(); } ProcessBuilder builder = new ProcessBuilder(LAME_FILE_DIR + LAME_FILENAME, LAME_OPTIONS, inputFile.getAbsolutePath(), outputFile.getAbsolutePath()); builder.directory(new File(LAME_FILE_DIR)).start(); System.out.println("Process: " + LAME_FILE_DIR + LAME_FILENAME + " " + LAME_OPTIONS + " " + inputFile.getAbsolutePath() + " " + outputFile.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); } } } else { System.err.println(DIR_TO_CONVERT + " is not a directory"); } } }
Указываем через константы путь к Lame (LAME_FILE_DIR), путь к *.mp3 файлам (DIR_TO_CONVERT), настройки Lame (LAME_OPTIONS), а также если нужно указываем префикс (PREFIX). Затем запускаем данный класс.
Увы, но Process.waitFor() упорно блокировал процесс и я так не разобрался почему.
Развертывание WAR в корне JBoss
Чтобы развернуть веб приложене (*.war) в корне JBoss (то есть ‘/’), необходимо:
- удалить ROOT.war в папке deploy (к примеру, у JBoss 6.0 это /server/default/deploy/)
- добавить jboss-web.xml в папку WEB-INF со следующим содержимым:
<?xml version="1.0" encoding="UTF-8"?> <jboss-web> <context-root /> </jboss-web>
Рестарт сервера и наше приложение доступно по адрес http://localhost:8080/.
Hibernate & PostgreSQL problems
Я только что начал новый проект и выбрал Intellij Idea 9.0.3 как среду для разработки, БД: PostgreSQL 8.4, сервер приложений: JBoss 6.0 m4.
Создадим простейший класс Customer.java:
@Entity() public class Customer { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Column() private String name; @Column() private String patronymic; @Column() private String surname; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPatronymic() { return patronymic; } public void setPatronymic(String patronymic) { this.patronymic = patronymic; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } }
and by default idea create a persistence.xml file for me:
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0"> <persistence-unit name="RavenPersistenceUnit"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/RavenDS</jta-data-source> <class>com.silverhaze.raven.common.data.Customer</class> <properties> <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/raven"/> <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/> <property name="hibernate.connection.username" value="postgres"/> <property name="hibernate.connection.password" value="password"/> <!--<property name="hibernate.archive.autodetection" value="class"/>--> <!--<property name="hibernate.show_sql" value="true"/>--> <!--<property name="hibernate.format_sql" value="true"/>--> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/> <property name="hbm2ddl.auto" value="update"/> </properties> </persistence-unit> </persistence>
После развертывания приложения, я получаю следующую ошибку:
ERROR JDBCExceptionReporter:78 – ERROR: relation “hibernate_sequence” does not exist
Exception in thread “main” org.hibernate.exception.SQLGrammarException: could not get next sequence value
Решение простое, нужно просто добавить sequence в текущую БД:
CREATE SEQUENCE hibernate_sequence INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 33 CACHE 1; ALTER TABLE hibernate_sequence OWNER TO postgres;
После того как я попытался сохранить сущность Customer в БД, я обнаружил, что в БД отсутствует таблица customer, но Hibernate должен был создать её, так как я использовал следующие настройки:
<property name="hbm2ddl.auto" value="update"/>
Я просмотрел persistence.xml несколько раз и вроде бы всё корректно. После этого я решил перечитать документацию касательно hibernate properties и обнаружил ошибку. Проблема заключалась в том, что в persistence.xml, который по умолчанию сгенерировала IntelliJ IDEA был указан параметр hbm2ddl.auto вместо hibernate.hbm2ddl.auto.