Systém psaných i nepsanách konvencí které ovlivňují jakým způsobem se lidé staví k řešení probéml a jak se k sobě navzájem chovají.
neděle 23. listopadu 2014
DevFest 2014
středa 12. listopadu 2014
SQL Performance Explained
Protože se po večerech a víkendech snažím o zrychlování našeho systému JdemeNaTo, tak jsem zainvestoval €10 a začetl se.
Knížka detailně popisuje, jak funguje index a jaké jsou běžné chyby při používání. Příklady autor ukazuje hlavně na Oracle, ale alternativy i na jiných - např. moje oblíbená PostgreSQL.
Moc se mi líbí stručný a výstižný jazyk. Každá věta nese informaci. Nikde žádná zbytečná výplň.
Nové poznatky jsem ihned začal úspěšně aplikovat na naší databázi, která už není úplně malá (řádově miliony řádků).
Rozhodně doporučuji k prostudování a dokonce zvažuji, připlatit si za vytištěnou verzi.
neděle 8. června 2014
SQL Antipatterns
Při procházení knížek z nakladatelství The Pragmatic Bookshelf jsem narazil titul, který mě zaujal svým názvem.
Autor popisuje 24 vzorů na které naráží při používání klasických relačních databází. Problém popíše, navrhne možné řešení a s vědeckou metodičností rozebírá výhody a nevýhody jednotlivých variant.
Mě zaujaly dva vzory, které jsem mohl ihned aplikovat na projektu jdemenato.cz.
Enumerace
Standardním přístupem je enumeraci omezit pomocí omezení na sloupci.CREATE TABLE Bugs ( -- other columns status VARCHAR(20), status VARCHAR(20) check (status in ('NEW', 'IN PROGRESS', 'FIXED')) );Lepším řešením je ale vytáhnout celou enumeraci do nové tabulky, kde hodnota enumerace je přímo primárním klíčem.
CREATE TABLE BugStatus ( status VARCHAR(20) PRIMARY KEY ); INSERT INTO BugStatus (status) VALUES ('NEW' ), ('IN PROGRESS' ), ('FIXED' ); CREATE TABLE Bugs ( -- other columns status VARCHAR(20), FOREIGN KEY (status) REFERENCES BugStatus(status) ON UPDATE CASCADE );Lze se pak se pak krásně dotazovat na všechny hodnoty
SELECT status FROM BugStatus ORDER by status;Elegantně jdou přidávat nové hodnoty do enumerace i
INSERT INTO BugStatus (status) VALUES ('DUPLICATE' );a díky ON UPDATE CASCADE i nahrazovat nahrazovat historicky špatně zvolené.
UPDATE BugStatus SET status = 'INVALID' WHERE status = 'BOGUS' ;
Naivní stromy
Běžně jsem se setkal s tím, že stromovou struktura se řeší pomocí reference na sebe sama.CREATE TABLE Comments ( comment_id SERIAL PRIMARY KEY, parent_id BIGINT UNSIGNED, comment TEXT NOT NULL, FOREIGN KEY (parent_id) REFERENCES Comments(comment_id) );I pokud má vaše databáze podporu pro hierarchické dotazy, není to žádná hitparáda.
WITH CommentTree (comment_id, bug_id, parent_id, author, comment, depth) AS ( SELECT *, 0 AS depth FROM Comments WHERE parent_id IS NULL UNION ALL SELECT c.*, ct.depth+1 AS depth FROM CommentTree ct JOIN Comments c ON (ct.comment_id = c.parent_id) ) SELECT * FROM CommentTree WHERE bug_id = 1234;Autor popisuje několik variant, jak vazby ukládat. Mě osobně se nejvíce líbilo řešení pomocí closure table - doporučuji k nastudování.
sobota 12. dubna 2014
Spring configuration files - best practice
I prefer to configure spring with xml files. The question is, how they should be named and where should be located.
The official spring documentation do not provide any recommendation. Here are some with I advocate.
Name consistency
Start all files with the same prefix applicationConfig*.xml
E.g. applicationConfig-security.xml
, applicationConfig-hibernate.xml
, applicationConfig-quartz.xml
etc.
File Location
- JAR ->
src/main/resources/META-INF/spring
- WAR ->
src/main/webapp/WEB-INF/spring
Do not use version number in schema reference
Instead of
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> ... </beans>
Use this
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> ... </beans>
Why?
Spring automatically use highest version available from maven dependencies. Upgrade to newer version of spring is much more easy.
středa 2. dubna 2014
Řízení transakcí přes různé DAO implementace
V produkčním režimu, kde nám neustále roste počet uživatelů, jsme s tímto naivním řešením vydrželi jen několik měsíců. Kritické dotazy, které nejvíce vytěžovaly databázi, jsem přepsali přes Criteria API na "lepší" SQL dotazy.
Po dalších měsících produkčního života nás zákaznické požadavky přinutili některé SQL dotazy psát ručně. Nejprimitivnější jsme zrealizovali přes Hibernate native SQL ale u složitějších jsme šáhli na JdbcTemplate a později k MyBatis.
To ovšem nastolilo problém s řízením databázových transakcí, jejichž součástí je více DAO technologií.
Ukázalo se, že na podobné případy chlapci ve springu pamatovali a stačilo vyměnit HibernateTransacionManager za DataSourceTransactionManager.
Tímto způsobem je DataSource "nejmenším společním jmenovatelem" spojující DAOs implementované přes Hibernate, MyBatis i JdbcTemplate.
Aby si
AnnotationSessionFactoryBean
nevytvořila svůj vlastní transakční manager, je nutné nastavit ji property useTransactionAwareDataSource=true.
<bean name="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="useTransactionAwareDataSource" value="true"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="configLocation" value="classpath:/META-INF/mybatis/myBatis-configuration.xml"/> </bean>