вторник, 25 мая 2010 г.

Начало работы с JSF 2

Вот небольшой список ссылок где можно найти полезную инфу о JSF 2 по мимо туториала :)


Поддержка JSF 2.0 в среде IDE NetBeans версии 6.8
Начало работы с приложениями Java EE 6
DevelopJavaEE6App
DevelopAjaxJSF2App
Java EE 6 Pet Catalog with GlassFish v3 preview and MySQL
JSF 2 fu, Part 2: Templating and composite components
http://www.ibm.com/developerworks/ru/library/0707_barcia/
This document had no style information.
ejb-local-ref
Document Information
Сушночти в JSF и Хронимые процедуры баз данных
Пример работы с Хронимыми процедурами от NetBeans
Презенташка от Sun по анатациям

Java и Хронимые процедуры MS SQL Server

По необходимости пришлось связать свою судьбу с Java =)
Если чесно пока об этом не желею. При решении задачь исмользую сервер баз данных на MS SQL 2005. Драйвера доступа (JDBC) скачал с офф. сайта www.microsoft.com

В данном посте расматривается задача об использовании в Java хронимых процедур из SQL Server.
При написании данного класса у меня возникла проблема. Хронимая процедура выполняет разузловку изделия и выводит таблицу вхождения материалов в изделие (Он приводился в более ранних постах). Процедура иполнена в стиле CURSORO-в в связи с этим возникли затруднения при решении задачи.


import java.sql.*;
import com.microsoft.sqlserver.jdbc.*;

public class connectDS {

public static void main(String[] args) {

// Declare the JDBC objects.
Connection con = null;
CallableStatement cstmt = null;
ResultSet rs = null;

try {
// Establish the connection.
SQLServerDataSource ds = new SQLServerDataSource();
ds.setUser("sa");
ds.setPassword("MyPass");
ds.setServerName("127.0.0.1");
ds.setPortNumber(1433);
ds.setDatabaseName("pubs");
con = ds.getConnection();

// Execute a stored procedure that returns some data.
cstmt = con.prepareCall("{call dbo.RET_ShowStructItem1(?)}");
cstmt.setString(1, "3.020.324.007-001");
cstmt.execute();

while (!cstmt.getMoreResults() && (cstmt.getUpdateCount() != -1)) {
}

rs = cstmt.getResultSet();


while (rs.next()) {
System.out.println(rs.getString("item"));
System.out.println(rs.getString("description"));
System.out.println();
}
} // Handle any errors that may have occurred.
catch (Exception e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
}
}
if (cstmt != null) {
try {
cstmt.close();
} catch (Exception e) {
}
}
if (con != null) {
try {
con.close();
} catch (Exception e) {
}
}
System.exit(1);
}
}
}


Данный код приведенный выше работает и уже модефицированн.
Проблема заключается в том что процедура в момент обработки при каждом выполнении (INSERT, UPDATE, SELECT) возвращает результат выполнения это можно отключить в процедуре командой SET NOCOUNT ON либо при написании класса использовать цикл

while (!cstmt.getMoreResults() && (cstmt.getUpdateCount() != -1)) {}


Для коректности лудше вставить туда обработчики исключений.

P.S.:Пример от Microsoft

Старые CURSOR или новые WITH

Долгое время приходилось работать на SQL Server 2000 SP4. Также была необходимость сопровождать тот код что был написан до меня. После продолжительного времени работы мы перешли на SQL Server 2005 что открыло новые возможности и новый функционал. При его освоении начали переписывать старые наработки.

Задача:
Написать процедуру которая принемает параметр (Изделие item) и производит его разузловку (строит дерево вхождений)

Вопросы:
1. Как это делается ?
2. Есть ли смысл в переходе на нововведения ?

Парктика.
[SQL Server 2000] Что было в начале....

CREATE PROCEDURE [dbo].[MyProcSp] (@item NVARCHAR(255) = NULL)
AS
DECLARE @Col DECIMAL(10,5)
DECLARE @NowStartDate DATETIME
DECLARE @Item1 NVARCHAR(50)
DECLARE @pos SMALLINT

SET @NowStartDate = GETDATE()

IF OBJECT_ID('tempdb..#ItmTableTmp') IS NULL
BEGIN
CREATE TABLE #ItmTableTmp (item nvarchar(50)
, itemSub nvarchar(50)
, u_m nvarchar(3)
, Qty decimal(10,5)
, Level int
, P_M_T_Code nvarchar (1))
END

INSERT INTO #RET_STItem
SELECT @item, jm.item, i1.u_m, jm.matl_qty, @pos, i1.p_m_t_code
FROM item i
INNER JOIN job j ON (i.item=j.item) AND (i.job = j.job) AND (i.suffix = j.suffix) AND (j.type = 'S')
INNER JOIN jobmatl jm ON (jm.job = j.job) AND (jm.suffix = j.suffix)
INNER JOIN item i1 ON i1.item = jm.item
WHERE i.item = @item
AND jm.alt_group_rank = 0
ORDER BY jm.sequence

DECLARE @itemSub NVARCHAR(255)
DECLARE @posNext SMALLINT
DECLARE @p_m_t_code NVARCHAR(2)
SET @posNext=@pos+1


DECLARE c_cur CURSOR LOCAL STATIC FOR SELECT itemsub, qtyBase, p_m_t_code FROM #RET_STItem WHERE Level=@Pos and item=@item
OPEN c_cur
FETCH NEXT FROM c_cur INTO @itemSub,@Col,@p_m_t_code
WHILE @@Fetch_status=0
BEGIN
IF (DATEDIFF(mi, @NowStartDate, GETDATE()) < 31)
BEGIN
IF @p_m_t_code='M' EXEC [DBO].[RET_ShowStructItem1] @itemSub, @posNext,@Col
END
FETCH NEXT FROM c_cur INTO @itemSub,@Col,@p_m_t_code
END
CLOSE c_cur
DEALLOCATE c_cur

SELECT r.item
, i1.description
, r.QtyConst
, level

FROM #RET_STItem r
INNER JOIN item i ON i.item=r.itemsub
INNER JOIN item i1 ON i1.item=r.item
ORDER BY r.level, r.item, r.seq


Альтернативный вариант, написан на SQL Server 2005

CREATE PROCEDURE [dbo].[MyProcSp] (@item NVARCHAR(255) = NULL)
AS
DECLARE @pos SMALLINT

WITH RptOut (item, itemSub, u_m, Qty, Level, P_M_T_Code)
AS
(
-- Оригинал
SELECT i.item
, jm.item
, i1.u_m
, jm.qty
, rp.Level + 1
, i1.p_m_t_code

FROM item i
INNER JOIN job j ON (i.item=j.item) and (i.job=j.job) and (i.suffix=j.suffix) and (j.type='S')
INNER JOIN jobmatl jm ON (jm.job=j.job) and (jm.suffix=j.suffix)
INNER JOIN item i1 ON i1.item=jm.item

WHERE i.item=@item
AND jm.alt_group_rank = 0

UNION ALL

-- Рекурсия
SELECT i.item
, jm.item
, i1.u_m
, jm.qty
, rp.Level + 1
, i1.p_m_t_code

FROM item i
INNER JOIN job j ON (i.item=j.item) and (i.job=j.job) and (i.suffix=j.suffix) and (j.type='S')
INNER JOIN jobmatl jm ON (jm.job=j.job) and (jm.suffix=j.suffix)
INNER JOIN item i1 ON i1.item=jm.item
INNER JOIN RptOut rp ON rp.itemSub = i.item

WHERE jm.alt_group_rank = 0
)

SELECT * FROM RptOut


Как это делается показано выше, а вот есть ли смысл.....

Проводил тест на статичной базе (в базе работал только 1 пользователь) по изделию в который входит более 1500 вхождений.

Старые наработки [CURSOR] => выполнилось за 326 мс
Новый вариант [WITH] => выполнилось за 216 мс

В среднем прирост получается 33%

Статичной базе сильно незаметна выгода, а в активно рабочей базе прирост будет ощутим.

P.S.: Первый код (CURSOR) взят с рабочей базы и был изсправлен, в связи с этим
некоторые данные не совподают ;)
Со временем поправлю


Практика показала что если использовать WITH то Таблица которую он создает, может использоватся толька 1 раз. Либо ее необходимо поместить во временную таблюцу.

Что это и зачем....

Данный блог, является записной книжкой. По работе приходится узнавать новые технологии, проводить тесты и сравнения, для хранения результатов решил создать данный блог дабы здесь выкладывать все свои находки и раскопки :)