The important thing in life is to have a great aim , and the determination

常用链接

统计

IT技术链接

保险相关

友情链接

基金知识

生活相关

最新评论

#

Spring多数据源解决方案

在很多大型应用中都会对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。

 

Figure 1 数据分割及多数据库架构

    通常这种多数据源的逻辑会渗透到业务逻辑中,同时也会给我们使用的数据访问API诸如Hibernate和iBatis等带来不便(需要指定多个SessionFactory或SqlMapClient实例来对应多个DataSource)。


Figure 2 多数据源的选择逻辑渗透至客户端

 

    解决方案


Figure 3 采用Proxy模式来封装数据源选择逻辑

    通过采用Proxy模式我们在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。

    Client提供选择所需的上下文(因为这是Client所知道的),由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。

    Spring2.x的版本中提供了实现这种方式的基本框架,虚拟的DataSource仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey()在其中封装数据源的选择逻辑。

    实例:

publicclass DynamicDataSource extends AbstractRoutingDataSource {

      static Logger log = Logger.getLogger("DynamicDataSource");

      @Override

      protected Object determineCurrentLookupKey() {

            String userId=(String)DbContextHolder.getContext();

            Integer dataSourceId=getDataSourceIdByUserId(userId);

            return dataSourceId;

      }

}

    实例中通过UserId来决定数据存放在哪个数据库中。

    配置文件示例:

<bean id="dataSource" class="com.bitfone.smartdm.datasource.DynamicDataSource">

              <property name="targetDataSources">

                 <map key-type="java.lang.Integer">

                    <entry key="0" value-ref="dataSource0"/>

                    <entry key="1" value-ref="dataSource1"/>

                    <entry key="2" value-ref="dataSource2"/>

                 </map>

              </property>

              <property name="defaultTargetDataSource" ref="dataSource0"/>

            </bean>

            <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">

                <property name="configLocation" value="classpath:com/bitfone/smartdm/dao/sqlmap/sql-map-config.xml"/>

                <property name="dataSource" ref="dataSource"/>

           </bean>

            <bean id="UserInfoDAO" class="com.bitfone.smartdm.dao.impl.UserInfoDAO">

 

                  <property name="sqlMapClient" ref="sqlMapClient"/>

            </bean>

posted @ 2010-07-14 17:10 鸿雁 阅读(123) | 评论 (0)编辑 收藏

使用JAVA中的动态代理实现数据库连接池(转自developerWorks )

     摘要:   通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池。 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的连接数据库对服务性能来讲是一个瓶颈,使用缓冲池技术可以来消除这个瓶颈。我们可以在互联网上找到很多关于数据库连接池的源程序,但是都发现这样一个共同的问题:这些连接池的实现方法都不同程度地增加了与使用者之间的耦合度。很多的连...  阅读全文

posted @ 2010-07-14 17:08 鸿雁 阅读(142) | 评论 (0)编辑 收藏

jfreechart 生成折线图,饼图,柱状图,堆栈柱状图(转自javaEye)

1.所需包
(1) jfreechart-1.0.8a.jar
(2) jcommon-1.0.12.jar
2.运行环境
JDK 1.5

3.源代码

import java.awt.Color;
import java.awt.Font;
import java.io.File;
import java.io.FileOutputStream;
import java.text.DecimalFormat;
import java.text.NumberFormat;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot3D;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StackedBarRenderer;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;

/**
* 实际取色的时候一定要16位的,这样比较准确
*
* @author new
*/
public class CreateChartServiceImpl
{
private static final String CHART_PATH = "E:/test/";

public static void main(String[] args)
{
// TODO Auto-generated method stub
CreateChartServiceImpl pm = new CreateChartServiceImpl();
// 生成饼状图
pm.makePieChart();
// 生成单组柱状图
pm.makeBarChart();
// 生成多组柱状图
pm.makeBarGroupChart();
// 生成堆积柱状图
pm.makeStackedBarChart();
// 生成折线图
pm.makeLineAndShapeChart();
}

/**
* 生成折线图
*/
public void makeLineAndShapeChart()
{
double[][] data = new double[][]
{
{ 672, 766, 223, 540, 126 },
{ 325, 521, 210, 340, 106 },
{ 332, 256, 523, 240, 526 } };
String[] rowKeys =
{ "苹果", "梨子", "葡萄" };
String[] columnKeys =
{ "北京", "上海", "广州", "成都", "深圳" };
CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
createTimeXYChar("折线图", "x轴", "y轴", dataset, "lineAndShap.png");
}

/**
* 生成分组的柱状图
*/
public void makeBarGroupChart()
{
double[][] data = new double[][]
{
{ 672, 766, 223, 540, 126 },
{ 325, 521, 210, 340, 106 },
{ 332, 256, 523, 240, 526 } };
String[] rowKeys =
{ "苹果", "梨子", "葡萄" };
String[] columnKeys =
{ "北京", "上海", "广州", "成都", "深圳" };
CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
createBarChart(dataset, "x坐标", "y坐标", "柱状图", "barGroup.png");
}

/**
* 生成柱状图
*/
public void makeBarChart()
{
double[][] data = new double[][]
{
{ 672, 766, 223, 540, 126 } };
String[] rowKeys =
{ "苹果" };
String[] columnKeys =
{ "北京", "上海", "广州", "成都", "深圳" };
CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
createBarChart(dataset, "x坐标", "y坐标", "柱状图", "bar.png");
}

/**
* 生成堆栈柱状图
*/
public void makeStackedBarChart()
{
double[][] data = new double[][]
{
{ 0.21, 0.66, 0.23, 0.40, 0.26 },
{ 0.25, 0.21, 0.10, 0.40, 0.16 } };
String[] rowKeys =
{ "苹果", "梨子" };
String[] columnKeys =
{ "北京", "上海", "广州", "成都", "深圳" };
CategoryDataset dataset = getBarData(data, rowKeys, columnKeys);
createStackedBarChart(dataset, "x坐标", "y坐标", "柱状图", "stsckedBar.png");
}

/**
* 生成饼状图
*/
public void makePieChart()
{
double[] data =
{ 9, 91 };
String[] keys =
{ "失败率", "成功率" };

createValidityComparePimChar(getDataPieSetByUtil(data, keys), "饼状图",
        "pie2.png", keys);
}

// 柱状图,折线图 数据集
public CategoryDataset getBarData(double[][] data, String[] rowKeys,
        String[] columnKeys)
{
return DatasetUtilities
        .createCategoryDataset(rowKeys, columnKeys, data);

}

// 饼状图 数据集
public PieDataset getDataPieSetByUtil(double[] data,
        String[] datadescription)
{

if (data != null && datadescription != null)
{
if (data.length == datadescription.length)
{
DefaultPieDataset dataset = new DefaultPieDataset();
for (int i = 0; i < data.length; i++)
{
dataset.setValue(datadescription[i], data[i]);
}
return dataset;
}

}

return null;
}

/**
* 柱状图
*
*@param dataset 数据集
* @param xName x轴的说明(如种类,时间等)
* @param yName y轴的说明(如速度,时间等)
* @param chartTitle 图标题
* @param charName 生成图片的名字
* @return
*/
public String createBarChart(CategoryDataset dataset, String xName,
        String yName, String chartTitle, String charName)
{
JFreeChart chart = ChartFactory.createBarChart(chartTitle, // 图表标题
        xName, // 目录轴的显示标签
        yName, // 数值轴的显示标签
        dataset, // 数据集
        PlotOrientation.VERTICAL, // 图表方向:水平、垂直
        true, // 是否显示图例(对于简单的柱状图必须是false)
        false, // 是否生成工具
        false // 是否生成URL链接
        );
Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);
/*
* VALUE_TEXT_ANTIALIAS_OFF表示将文字的抗锯齿关闭,
* 使用的关闭抗锯齿后,字体尽量选择12到14号的宋体字,这样文字最清晰好看
*/
// chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
chart.setTextAntiAlias(false);
chart.setBackgroundPaint(Color.white);
// create plot
CategoryPlot plot = chart.getCategoryPlot();
// 设置横虚线可见
plot.setRangeGridlinesVisible(true);
// 虚线色彩
plot.setRangeGridlinePaint(Color.gray);

// 数据轴精度
NumberAxis vn = (NumberAxis) plot.getRangeAxis();
// vn.setAutoRangeIncludesZero(true);
DecimalFormat df = new DecimalFormat("#0.00");
vn.setNumberFormatOverride(df); // 数据轴数据标签的显示格式
// x轴设置
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setLabelFont(labelFont);// 轴标题
domainAxis.setTickLabelFont(labelFont);// 轴数值

// Lable(Math.PI/3.0)度倾斜
// domainAxis.setCategoryLabelPositions(CategoryLabelPositions
// .createUpRotationLabelPositions(Math.PI / 3.0));

domainAxis.setMaximumCategoryLabelWidthRatio(0.6f);// 横轴上的 Lable 是否完整显示

// 设置距离图片左端距离
domainAxis.setLowerMargin(0.1);
// 设置距离图片右端距离
domainAxis.setUpperMargin(0.1);
// 设置 columnKey 是否间隔显示
// domainAxis.setSkipCategoryLabelsToFit(true);

plot.setDomainAxis(domainAxis);
// 设置柱图背景色(注意,系统取色的时候要使用16位的模式来查看颜色编码,这样比较准确)
plot.setBackgroundPaint(new Color(255, 255, 204));

// y轴设置
ValueAxis rangeAxis = plot.getRangeAxis();
rangeAxis.setLabelFont(labelFont);
rangeAxis.setTickLabelFont(labelFont);
// 设置最高的一个 Item 与图片顶端的距离
rangeAxis.setUpperMargin(0.15);
// 设置最低的一个 Item 与图片底端的距离
rangeAxis.setLowerMargin(0.15);
plot.setRangeAxis(rangeAxis);

BarRenderer renderer = new BarRenderer();
// 设置柱子宽度
renderer.setMaximumBarWidth(0.05);
// 设置柱子高度
renderer.setMinimumBarLength(0.2);
// 设置柱子边框颜色
renderer.setBaseOutlinePaint(Color.BLACK);
// 设置柱子边框可见
renderer.setDrawBarOutline(true);

// // 设置柱的颜色
renderer.setSeriesPaint(0, new Color(204, 255, 255));
renderer.setSeriesPaint(1, new Color(153, 204, 255));
renderer.setSeriesPaint(2, new Color(51, 204, 204));

// 设置每个地区所包含的平行柱的之间距离
renderer.setItemMargin(0.0);

// 显示每个柱的数值,并修改该数值的字体属性
renderer.setIncludeBaseInRange(true);
renderer
        .setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
renderer.setBaseItemLabelsVisible(true);

plot.setRenderer(renderer);
// 设置柱的透明度
plot.setForegroundAlpha(1.0f);

FileOutputStream fos_jpg = null;
try
{
isChartPathExist(CHART_PATH);
String chartName = CHART_PATH + charName;
fos_jpg = new FileOutputStream(chartName);
ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 500, true, 10);
return chartName;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
finally
{
try
{
fos_jpg.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

/**
* 横向图
*
* @param dataset 数据集
* @param xName x轴的说明(如种类,时间等)
* @param yName y轴的说明(如速度,时间等)
* @param chartTitle 图标题
* @param charName 生成图片的名字
* @return
*/
public String createHorizontalBarChart(CategoryDataset dataset,
        String xName, String yName, String chartTitle, String charName)
{
JFreeChart chart = ChartFactory.createBarChart(chartTitle, // 图表标题
        xName, // 目录轴的显示标签
        yName, // 数值轴的显示标签
        dataset, // 数据集
        PlotOrientation.VERTICAL, // 图表方向:水平、垂直
        true, // 是否显示图例(对于简单的柱状图必须是false)
        false, // 是否生成工具
        false // 是否生成URL链接
        );

CategoryPlot plot = chart.getCategoryPlot();
// 数据轴精度
NumberAxis vn = (NumberAxis) plot.getRangeAxis();
//设置刻度必须从0开始
// vn.setAutoRangeIncludesZero(true);
DecimalFormat df = new DecimalFormat("#0.00");
vn.setNumberFormatOverride(df); // 数据轴数据标签的显示格式

CategoryAxis domainAxis = plot.getDomainAxis();

domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 横轴上的
// Lable
Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);

domainAxis.setLabelFont(labelFont);// 轴标题
domainAxis.setTickLabelFont(labelFont);// 轴数值

domainAxis.setMaximumCategoryLabelWidthRatio(0.8f);// 横轴上的 Lable 是否完整显示
// domainAxis.setVerticalCategoryLabels(false);
plot.setDomainAxis(domainAxis);

ValueAxis rangeAxis = plot.getRangeAxis();
// 设置最高的一个 Item 与图片顶端的距离
rangeAxis.setUpperMargin(0.15);
// 设置最低的一个 Item 与图片底端的距离
rangeAxis.setLowerMargin(0.15);
plot.setRangeAxis(rangeAxis);
BarRenderer renderer = new BarRenderer();
// 设置柱子宽度
renderer.setMaximumBarWidth(0.03);
// 设置柱子高度
renderer.setMinimumBarLength(30);

renderer.setBaseOutlinePaint(Color.BLACK);

// 设置柱的颜色
renderer.setSeriesPaint(0, Color.GREEN);
renderer.setSeriesPaint(1, new Color(0, 0, 255));
// 设置每个地区所包含的平行柱的之间距离
renderer.setItemMargin(0.5);
// 显示每个柱的数值,并修改该数值的字体属性
renderer
        .setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
// 设置柱的数值可见
renderer.setBaseItemLabelsVisible(true);

plot.setRenderer(renderer);
// 设置柱的透明度
plot.setForegroundAlpha(0.6f);

FileOutputStream fos_jpg = null;
try
{
isChartPathExist(CHART_PATH);
String chartName = CHART_PATH + charName;
fos_jpg = new FileOutputStream(chartName);
ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 500, true, 10);
return chartName;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
finally
{
try
{
fos_jpg.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

/**
* 饼状图
*
* @param dataset 数据集
* @param chartTitle 图标题
* @param charName 生成图的名字
* @param pieKeys 分饼的名字集
* @return
*/
public String createValidityComparePimChar(PieDataset dataset,
        String chartTitle, String charName, String[] pieKeys)
{
JFreeChart chart = ChartFactory.createPieChart3D(chartTitle, // chart
        // title
        dataset,// data
        true,// include legend
        true, false);

// 使下说明标签字体清晰,去锯齿类似于
// chart.getRenderingHints().put(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);的效果
chart.setTextAntiAlias(false);
// 图片背景色
chart.setBackgroundPaint(Color.white);
// 设置图标题的字体重新设置title
Font font = new Font("隶书", Font.BOLD, 25);
TextTitle title = new TextTitle(chartTitle);
title.setFont(font);
chart.setTitle(title);

PiePlot3D plot = (PiePlot3D) chart.getPlot();
// 图片中显示百分比:默认方式

// 指定饼图轮廓线的颜色
// plot.setBaseSectionOutlinePaint(Color.BLACK);
// plot.setBaseSectionPaint(Color.BLACK);

// 设置无数据时的信息
plot.setNoDataMessage("无对应的数据,请重新查询。");

// 设置无数据时的信息显示颜色
plot.setNoDataMessagePaint(Color.red);

// 图片中显示百分比:自定义方式,{0} 表示选项, {1} 表示数值, {2} 表示所占比例 ,小数点后两位
plot.setLabelGenerator(new StandardPieSectionLabelGenerator(
        "{0}={1}({2})", NumberFormat.getNumberInstance(),
        new DecimalFormat("0.00%")));
// 图例显示百分比:自定义方式, {0} 表示选项, {1} 表示数值, {2} 表示所占比例
plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator(
        "{0}={1}({2})"));

plot.setLabelFont(new Font("SansSerif", Font.TRUETYPE_FONT, 12));

// 指定图片的透明度(0.0-1.0)
plot.setForegroundAlpha(0.65f);
// 指定显示的饼图上圆形(false)还椭圆形(true)
plot.setCircular(false, true);

// 设置第一个 饼块section 的开始位置,默认是12点钟方向
plot.setStartAngle(90);

// // 设置分饼颜色
plot.setSectionPaint(pieKeys[0], new Color(244, 194, 144));
plot.setSectionPaint(pieKeys[1], new Color(144, 233, 144));

FileOutputStream fos_jpg = null;
try
{
// 文件夹不存在则创建
isChartPathExist(CHART_PATH);
String chartName = CHART_PATH + charName;
fos_jpg = new FileOutputStream(chartName);
// 高宽的设置影响椭圆饼图的形状
ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 230);

return chartName;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
finally
{
try
{
fos_jpg.close();
System.out.println("create pie-chart.");
}
catch (Exception e)
{
e.printStackTrace();
}
}

}

/**
* 判断文件夹是否存在,如果不存在则新建
* @param chartPath
*/
private void isChartPathExist(String chartPath)
{
File file = new File(chartPath);
if (!file.exists())
{
file.mkdirs();
// log.info("CHART_PATH="+CHART_PATH+"create.");
}
}

/**
* 折线图
*
* @param chartTitle
* @param x
* @param y
* @param xyDataset
* @param charName
* @return
*/
public String createTimeXYChar(String chartTitle, String x, String y,
        CategoryDataset xyDataset, String charName)
{

JFreeChart chart = ChartFactory.createLineChart(chartTitle, x, y,
        xyDataset, PlotOrientation.VERTICAL, true, true, false);

chart.setTextAntiAlias(false);
chart.setBackgroundPaint(Color.WHITE);
// 设置图标题的字体重新设置title
Font font = new Font("隶书", Font.BOLD, 25);
TextTitle title = new TextTitle(chartTitle);
title.setFont(font);
chart.setTitle(title);
// 设置面板字体
Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);

chart.setBackgroundPaint(Color.WHITE);

CategoryPlot categoryplot = (CategoryPlot) chart.getPlot();
// x轴 // 分类轴网格是否可见
categoryplot.setDomainGridlinesVisible(true);
// y轴 //数据轴网格是否可见
categoryplot.setRangeGridlinesVisible(true);

categoryplot.setRangeGridlinePaint(Color.WHITE);// 虚线色彩

categoryplot.setDomainGridlinePaint(Color.WHITE);// 虚线色彩

categoryplot.setBackgroundPaint(Color.lightGray);

// 设置轴和面板之间的距离
// categoryplot.setAxisOffset(new RectangleInsets(5D, 5D, 5D, 5D));

CategoryAxis domainAxis = categoryplot.getDomainAxis();

domainAxis.setLabelFont(labelFont);// 轴标题
domainAxis.setTickLabelFont(labelFont);// 轴数值

domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); // 横轴上的
// Lable
// 45度倾斜
// 设置距离图片左端距离
domainAxis.setLowerMargin(0.0);
// 设置距离图片右端距离
domainAxis.setUpperMargin(0.0);

NumberAxis numberaxis = (NumberAxis) categoryplot.getRangeAxis();
numberaxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
numberaxis.setAutoRangeIncludesZero(true);

// 获得renderer 注意这里是下嗍造型到lineandshaperenderer!!
LineAndShapeRenderer lineandshaperenderer = (LineAndShapeRenderer) categoryplot
        .getRenderer();

lineandshaperenderer.setBaseShapesVisible(true); // series 点(即数据点)可见
lineandshaperenderer.setBaseLinesVisible(true); // series 点(即数据点)间有连线可见

// 显示折点数据
// lineandshaperenderer.setBaseItemLabelGenerator(new
// StandardCategoryItemLabelGenerator());
// lineandshaperenderer.setBaseItemLabelsVisible(true);

FileOutputStream fos_jpg = null;
try
{
isChartPathExist(CHART_PATH);
String chartName = CHART_PATH + charName;
fos_jpg = new FileOutputStream(chartName);

// 将报表保存为png文件
ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 510);

return chartName;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
finally
{
try
{
fos_jpg.close();
System.out.println("create time-createTimeXYChar.");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

/**
* 堆栈柱状图
*
* @param dataset
* @param xName
* @param yName
* @param chartTitle
* @param charName
* @return
*/
public String createStackedBarChart(CategoryDataset dataset, String xName,
        String yName, String chartTitle, String charName)
{
// 1:得到 CategoryDataset

// 2:JFreeChart对象
JFreeChart chart = ChartFactory.createStackedBarChart(chartTitle, // 图表标题
        xName, // 目录轴的显示标签
        yName, // 数值轴的显示标签
        dataset, // 数据集
        PlotOrientation.VERTICAL, // 图表方向:水平、垂直
        true, // 是否显示图例(对于简单的柱状图必须是false)
        false, // 是否生成工具
        false // 是否生成URL链接
        );
// 图例字体清晰
chart.setTextAntiAlias(false);

chart.setBackgroundPaint(Color.WHITE);

// 2 .2 主标题对象 主标题对象是 TextTitle 类型
chart
        .setTitle(new TextTitle(chartTitle, new Font("隶书", Font.BOLD,
                25)));
// 2 .2.1:设置中文
// x,y轴坐标字体
Font labelFont = new Font("SansSerif", Font.TRUETYPE_FONT, 12);

// 2 .3 Plot 对象 Plot 对象是图形的绘制结构对象
CategoryPlot plot = chart.getCategoryPlot();

// 设置横虚线可见
plot.setRangeGridlinesVisible(true);
// 虚线色彩
plot.setRangeGridlinePaint(Color.gray);

// 数据轴精度
NumberAxis vn = (NumberAxis) plot.getRangeAxis();
// 设置最大值是1
vn.setUpperBound(1);
// 设置数据轴坐标从0开始
// vn.setAutoRangeIncludesZero(true);
// 数据显示格式是百分比
DecimalFormat df = new DecimalFormat("0.00%");
vn.setNumberFormatOverride(df); // 数据轴数据标签的显示格式
// DomainAxis (区域轴,相当于 x 轴), RangeAxis (范围轴,相当于 y 轴)
CategoryAxis domainAxis = plot.getDomainAxis();

domainAxis.setLabelFont(labelFont);// 轴标题
domainAxis.setTickLabelFont(labelFont);// 轴数值

// x轴坐标太长,建议设置倾斜,如下两种方式选其一,两种效果相同
// 倾斜(1)横轴上的 Lable 45度倾斜
// domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
// 倾斜(2)Lable(Math.PI 3.0)度倾斜
// domainAxis.setCategoryLabelPositions(CategoryLabelPositions
// .createUpRotationLabelPositions(Math.PI / 3.0));

domainAxis.setMaximumCategoryLabelWidthRatio(0.6f);// 横轴上的 Lable 是否完整显示

plot.setDomainAxis(domainAxis);

// y轴设置
ValueAxis rangeAxis = plot.getRangeAxis();
rangeAxis.setLabelFont(labelFont);
rangeAxis.setTickLabelFont(labelFont);
// 设置最高的一个 Item 与图片顶端的距离
rangeAxis.setUpperMargin(0.15);
// 设置最低的一个 Item 与图片底端的距离
rangeAxis.setLowerMargin(0.15);
plot.setRangeAxis(rangeAxis);

// Renderer 对象是图形的绘制单元
StackedBarRenderer renderer = new StackedBarRenderer();
// 设置柱子宽度
renderer.setMaximumBarWidth(0.05);
// 设置柱子高度
renderer.setMinimumBarLength(0.1);
        //设置柱的边框颜色
renderer.setBaseOutlinePaint(Color.BLACK);
//设置柱的边框可见
renderer.setDrawBarOutline(true);

// // 设置柱的颜色(可设定也可默认)
renderer.setSeriesPaint(0, new Color(204, 255, 204));
renderer.setSeriesPaint(1, new Color(255, 204, 153));

// 设置每个地区所包含的平行柱的之间距离
renderer.setItemMargin(0.4);

plot.setRenderer(renderer);
// 设置柱的透明度(如果是3D的必须设置才能达到立体效果,如果是2D的设置则使颜色变淡)
// plot.setForegroundAlpha(0.65f);

FileOutputStream fos_jpg = null;
try
{
isChartPathExist(CHART_PATH);
String chartName = CHART_PATH + charName;
fos_jpg = new FileOutputStream(chartName);
ChartUtilities.writeChartAsPNG(fos_jpg, chart, 500, 500, true, 10);
return chartName;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
finally
{
try
{
fos_jpg.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}

}

posted @ 2009-11-12 15:25 鸿雁 阅读(942) | 评论 (0)编辑 收藏

阿里要走102年 阿里的工程师能走多远?(转)

很高兴看到阿里云的成立。这意味着阿里已经把对互联网技术的投入提高到了的战略高度。过去经常听工程师抱怨阿里不是一家技术公司。现在再没有理由可以这样抱怨了。但是要实现这个战略,没有技术储备是不行的。招聘和培养工程师显然是目前集团各子公司同时面临的一个令人头痛的难题。

由于曾经在硅谷工作过,我常想,为什么硅谷有这么多40岁以上的工程师,而国内30岁以上的就已经寥寥无几了?为什么硅谷的工程师的技术寿命可以这么长?为什么他们可以不浮躁,不急功近利呢?阿里要走102年,阿里的工程师可以一起走多远呢?

在国内,有2-3年工作经历的工程师就可以算有经验的了。工作了5年以上的工程师往往会考虑向管理岗位转型,或者向业务转型。中国目前处于高度发展的阶段。很多企业缺乏管理人才,工作5年就被提吧为干部很正常。但留下的后遗症是30岁以上的优秀技术人才极度缺乏。

在硅谷,5年以下工作经验的人都算是初级的。一般高级工程师需要5年以上的工作经验,架构师一般需要10年以上的工作经验。这还不算上大部分硅谷的工程师都有计算机硕士学位。毕业的时候一般已经是24,25岁了。再工作10年,35岁才升为架构师是非常正常的。然而,公司里的架构师有限。其实大部分 40岁的工程师仍然在一线工作,比如写程序,做测试,进行项目管理等。

美国硅谷是计算机人才集中的地方,也是创业公司群集的地方。在硅谷,从只有几个人到几十个人的创业公司比比皆是。他们的共同梦想就是经过几年的奋斗,通过技术的创新,再次缔造像英特尔,苹果,思科,甲骨文,雅虎,Google,Facebook等这样的神话。即使创造不了神话,也可以通过IPO或者被收购的途径创造财富。在这样的环境中,公司对管理人才的需求同样是非常大的,但为什么仍然有大量的工程师“无动于衷”,仍然从事着技术活儿呢?

我认为有两个主要原因。

一个是外因。在美国,管理岗位的待遇和技术岗位待遇相差不大。特别在崇尚技术的硅谷,经理的地位并不比工程师高,甚至更低。比如架构师在公司里的重要性往往要超过经理。因此管理岗位的“诱惑”并不大。在这样一种技术氛围中,走技术路线很正常。

但是即使在这样一个技术环境中,硅谷对管理人才依然需要。当工程师表现出色时,也有很多机会转成管理岗位。然而相当一部分工程师会主动放弃这样的机会,而继续干他们的技术活儿。这就是内因在驱动了。技术工作和管理工作的本质区别是,前者面对的是系统(软件,硬件等),而后者面对的是人。系统问题再难,只要有足够的时间和资源,一般都可以解决。越难的问题,解决之后越有成就感。而人的问题,有时候看似很简单,却解决不了。是人,总要有头疼脑热,生病的时候。是人,免不了产生情绪,从而影响工作。有人的地方,就会有矛盾,就会有摩擦。简单地讲,系统会按照事先设定的逻辑运行,是死的,因此往往可控,可规划。而人是活的,不是输入几条命令就可以控制的,而是需要沟通,需要感情的。因此,大部分硅谷的工程师很“聪明”。他们主动选择“简单”地工作。白天好好地工作,晚上好好地生活。何必去“自寻烦恼”,转做管理呢。

其实不光是硅谷的,其它地区的工程师都有一个共同的性格特点,追求简单,追求完美,思维方式上比较理性和逻辑性,看问题比较趋向于非黑即白。这样的性格非常适合做技术工作,可是我们中国的工程师有时候偏偏看不到自己的这个特点。

不想当元帅的士兵不是好士兵。工程师希望向管理方向发展是非常正常的。但问题是为什么和怎样?我碰到过不只一个工程师告诉我,希望转做管理的原因是担心今后年级大了,技术能力跟不上了。我觉得非常可笑。这就好比是一个士兵说:我杀敌本领不行,不适合上战场,那就让我做军官吧。一个没做过士兵的元帅肯定不是好元帅。其实做技术和当兵毕竟不同,不是靠体力吃饭的。年级大点往往是优势。

我觉得走技术路线对工程师性格的人是一条捷径。如果能静下心来仔细钻研技术,一定能在某个方面做得比别人好。这里的关键是好奇心和耐心。在今天这样的信息时代,找到答案并不是一件难事。难就难在有没有好奇心和耐心去找。比如,Java程序员天天都用到String这个类型。但有没有想过为什么 Java语言里有String和StringBuffer两种字符串类型,而不是一种?有没有去看过String和StringBuffer的源代码?再例如,天天做网站和HTTP打交道,有没有看过HTTP协议?有没有尝试过不用浏览器,wget等工具,而用最原始的telnet方式来访问网站?看看这 HTTP的头里到底是什么东东?在我面试过的工程师中,做过这几件事的人不到5%。

一旦了解得比别人深,就容易看到问题本质,产生信心,激发乐趣。这时候你的解决方案就比别人漂亮,逐渐建立起了影响力,成为了“专家”。因此公司里的疑难杂症会主动找上门来。你就比别人得到了更多的解决问题的机会,从而更快地提升能力。一旦进入良性循环,你的进步就比别人快,但付出的却不一定比别人多。这时候你已经走上了捷径。

在技术人才极度缺乏的中国,在众人盲目追求管理岗位的那点虚荣的今天,如果你的性格是工程师类型的,走技术路线其实是非常适合的。如果你才毕业,那你是最幸福的。你可以给自己制定3个甚至4个五年计划。例如5年打基础,10年变专家,15年国内知名,20年世界闻名。如果你已经奔三或者三十出头,那你快成熟了,但离开花结果还早呢。不信你看看下面几位我们都熟悉的人。

拉里-沃尔(Larry Wall)33岁时出版了《Perl语言编程》一书。之前他是一个系统管理员。

互联网之父温特-瑟夫(Vint Cerf)在发明TCP/IP时,已经35岁。

万维网之父蒂姆·伯纳斯—李(Tim Berners-Lee)在37岁时才发明了万维网(WWW)。

丹尼斯-里奇(Dennis Ritchie)的《C程序设计语言》一书出版时,他37岁。

Java之父詹姆斯·戈士林(James Gosling)40岁时才因为发明Java而成名。

苹果公司创始人之一史蒂夫?沃兹尼艾克(Steven Wozniak)在今年年初以首席科学家的身份加入一家创业公司,研发基于高速闪存技术的存储。他如今已经59岁了。

本文来源:百度博客

posted @ 2009-10-16 12:36 鸿雁 阅读(156) | 评论 (0)编辑 收藏

SQL SERVER convert函数日期格式化应用(转)

Sql Server 中一个非常强大的日期格式化函数
Select CONVERT(varchar(100), GETDATE(), 0): 05 16 2006 10:57AM
Select CONVERT(varchar(100), GETDATE(), 1): 05/16/06
Select CONVERT(varchar(100), GETDATE(), 2): 06.05.16
Select CONVERT(varchar(100), GETDATE(), 3): 16/05/06
Select CONVERT(varchar(100), GETDATE(), 4): 16.05.06
Select CONVERT(varchar(100), GETDATE(), 5): 16-05-06
Select CONVERT(varchar(100), GETDATE(), 6): 16 05 06
Select CONVERT(varchar(100), GETDATE(), 7): 05 16, 06
Select CONVERT(varchar(100), GETDATE(), 8): 10:57:46
Select CONVERT(varchar(100), GETDATE(), 9): 05 16 2006 10:57:46:827AM
Select CONVERT(varchar(100), GETDATE(), 10): 05-16-06
Select CONVERT(varchar(100), GETDATE(), 11): 06/05/16
Select CONVERT(varchar(100), GETDATE(), 12): 060516
Select CONVERT(varchar(100), GETDATE(), 13): 16 05 2006 10:57:46:937
Select CONVERT(varchar(100), GETDATE(), 14): 10:57:46:967
Select CONVERT(varchar(100), GETDATE(), 20): 2006-05-16 10:57:47
Select CONVERT(varchar(100), GETDATE(), 21): 2006-05-16 10:57:47.157
Select CONVERT(varchar(100), GETDATE(), 22): 05/16/06 10:57:47 AM
Select CONVERT(varchar(100), GETDATE(), 23): 2006-05-16
Select CONVERT(varchar(100), GETDATE(), 24): 10:57:47
Select CONVERT(varchar(100), GETDATE(), 25): 2006-05-16 10:57:47.250
Select CONVERT(varchar(100), GETDATE(), 100): 05 16 2006 10:57AM
Select CONVERT(varchar(100), GETDATE(), 101): 05/16/2006
Select CONVERT(varchar(100), GETDATE(), 102): 2006.05.16
Select CONVERT(varchar(100), GETDATE(), 103): 16/05/2006
Select CONVERT(varchar(100), GETDATE(), 104): 16.05.2006
Select CONVERT(varchar(100), GETDATE(), 105): 16-05-2006
Select CONVERT(varchar(100), GETDATE(), 106): 16 05 2006
Select CONVERT(varchar(100), GETDATE(), 107): 05 16, 2006
Select CONVERT(varchar(100), GETDATE(), 108): 10:57:49
Select CONVERT(varchar(100), GETDATE(), 109): 05 16 2006 10:57:49:437AM
Select CONVERT(varchar(100), GETDATE(), 110): 05-16-2006
Select CONVERT(varchar(100), GETDATE(), 111): 2006/05/16
Select CONVERT(varchar(100), GETDATE(), 112): 20060516
Select CONVERT(varchar(100), GETDATE(), 113): 16 05 2006 10:57:49:513
Select CONVERT(varchar(100), GETDATE(), 114): 10:57:49:547
Select CONVERT(varchar(100), GETDATE(), 120): 2006-05-16 10:57:49
Select CONVERT(varchar(100), GETDATE(), 121): 2006-05-16 10:57:49.700
Select CONVERT(varchar(100), GETDATE(), 126): 2006-05-16T10:57:49.827
Select CONVERT(varchar(100), GETDATE(), 130): 18 ???? ?????? 1427 10:57:49:907AM
Select CONVERT(varchar(100), GETDATE(), 131): 18/04/1427 10:57:49:920AM

posted @ 2009-09-23 15:14 鸿雁 阅读(176) | 评论 (0)编辑 收藏

oracle定时任务详解(转自CSDN)

 

DBMS_JOB系统包是Oracle“任务队列”子系统的API编程接口。DBMS_JOB包对于任务队列提供了下面这些功能:提交并且执行一个任务、改变任务的执行参数以及删除或者临时挂起任务等。

DBMS_JOB包是由ORACLE_HOME目录下的rdbms/admin子目录下的DBMSJOB.SQL和PRVTJOB.PLB 这两个脚本文件创建的。这两个文件被CATPROC.SQL脚本文件调用,而CATPROC.SQL这个文件一般是在数据库创建后立即执行的。脚本为DBMS_JOB包创建了一个公共同义词,并给该包授予了公共的可执行权限,所以所有的Oracle用户均可以使用这个包。

下面几个数据字典视图是关于任务队列信息的,主要有DBA_JOBS, USER_JOBS和DBA_JOBS_RUNNING。这些字典视图是由名为CATJOBQ.SQL的脚本文件创建的。该脚本文件和创建DBMS_JOB包的脚本文件一样在ORACLE_HOME目录的rdbms/admin子目录中,同样也是由脚本文件CATPROC.SQL调用。

最后,要使任务队列能正常运行,还必须启动它自己专有的后台过程。启动后台过程是通过在初始化文件init*.ora(实例不同,初始化文件名也略有不同)中设置初始化参数来进行的。下面就是该参数:

JOB_QUEUE_PROCESSES = n 

其中,n可以是0到36之间的任何一个数。除了该参数以外,还有几个关于任务队列的初始化参数,本文后面将会对其进行详细讨论。

DBMS_JOB包中包含有许多过程,见表1所示。

表1 DBMS_JOB包

 

名称 类型 描述
DBMS_JOB.ISUBMIT 过程 提交一个新任务,用户指定一个任务号
DBMS_JOB.SUBMIT 过程 提交一个新任务,系统指定一个任务号
DBMS_JOB.REMOVE 过程 从队列中删除一个已经存在的任务
DBMS_JOB.CHANGE 过程 更改用户设定的任务参数
DBMS_JOB.WHAT 过程 更改PL/SQL任务定义
DBMS_JOB.NEXT_DATE 过程 更改任务下一次运行时间
DBMS_JOB.INTERVAL 过程 更改任务运行的时间间隔
DBMS_JOB.BROKEN 过程 将任务挂起,不让其重复运行
DBMS_JOB.RUN 过程 在当前会话中立即执行任务
DBMS_JOB.USER_EXPORT 过程 创建文字字符串,用于重新创建一个任务

三、DBMS_JOB包参数

DBMS_JOB包中所有的过程都有一组相同的公共参数,用于定义任务,任务的运行时间以及任务定时运行的时间间隔。这些公共任务定义参数见表2所示。

表2 DBMS_JOB过程的公共参数

 

名称 类型 注释
Job BINARY_INTEGER 任务的唯一识别号
What VARCHAR2 作为任务执行的PL/SQL代码
Next_date VARCHAR2 任务下一次运行的时间
Interval VARCHAR2 日期表达式,用来计算下一次任务运行的时间

下面我们来详细讨论这些参数的意义及用法。

1、job

参数job是一个整数,用来唯一地标示一个任务。该参数既可由用户指定也可由系统自动赋予,这完全取决于提交任务时选用了那一个任务提交过程。DBMS_JOB.SUBMIT过程通过获得序列SYS.JOBSEQ的下一个值来自动赋予一个任务号。该任务号是作为一个OUT参数返回的,所以调用者随后可以识别出提交的任务。而DBMS_JOB.ISUBMIT过程则由调用者给任务指定一个识别号,这时候,任务号的唯一性就完全取决于调用者了。

除了删除或者重新提交任务,一般来说任务号是不能改变的。即使当数据库被导出或者被导入这样极端的情况,任务号也将被保留下来。所以在执行含有任务的数据的导入/导出操作时很可能会发生任务号冲突的现象。

2、what

what参数是一个可以转化为合法PL/SQL调用的字符串,该调用将被任务队列自动执行。在what参数中,如果使用文字字符串,则该字符串必须用单引号括起来。 what参数也可以使用包含我们所需要字符串值的VARCHAR2变量。实际的PL/SQL调用必须用分号隔开。在PL/SQL调用中如果要嵌入文字字符串,则必须使用两个单引号。

what参数的长度在Oracle7.3中限制在2000个字节以内,在Oracle 8.0以后,扩大到了4000个字节,这对于一般的应用已完全足够。该参数的值一般情况下都是对一个PL/SQL存储过程的调用。在实际应用中,尽管可以使用大匿名Pl/SQL块,但建议大家最好不要这样使用。还有一个实际经验就是最好将存储过程调用封装在一个匿名块中,这样可以避免一些比较莫名错误的产生。我来举一个例子,一般情况下,what参数可以这样引用:

 

what =>’my_procedure(parameter1);’

但是比较安全的引用,应该这样写:

what =>’begin my_procedure(parameter1); end;’

任何时候,我们只要通过更改what参数就可以达到更改任务定义的目的。但是有一点需要注意,通过改变what参数来改变任务定义时,用户当前的会话设置也被记录下来并成为任务运行环境的一部分。如果当前会话设置和最初提交任务时的会话设置不同,就有可能改变任务的运行行为。意识到这个潜在的副作用是非常重要的,无论何时只要应用到任何DBMS_JOB过程中的what参数时就一定要确保会话设置的正确。

3、next_date

Next_date参数是用来调度任务队列中该任务下一次运行的时间。这个参数对于DBMS_JOB.SUBMIT和DBMS_JOB.BROKEN这两个过程确省为系统当前时间,也就是说任务将立即运行。

当将一个任务的next_date参数赋值为null时,则该任务下一次运行的时间将被指定为4000年1月1日,也就是说该任务将永远不再运行。在大多数情况下,这可能是我们不愿意看到的情形。但是,换一个角度来考虑,如果想在任务队列中保留该任务而又不想让其运行,将next_date设置为null却是一个非常简单的办法。

Next_date也可以设置为过去的一个时间。这里要注意,系统任务的执行顺序是根据它们下一次的执行时间来确定的,于是将next_date参数设置回去就可以达到将该任务排在任务队列前面的目的。这在任务队列进程不能跟上将要执行的任务并且一个特定的任务需要尽快执行时是非常有用的。

4、Interval

Internal参数是一个表示Oracle合法日期表达式的字符串。这个日期字符串的值在每次任务被执行时算出,算出的日期表达式有两种可能,要么是未来的一个时间要么就是null。这里要强调一点:很多开发者都没有意识到next_date是在一个任务开始时算出的,而不是在任务成功完成时算出的。

当任务成功完成时,系统通过更新任务队列目录表将前面算出的next_date值置为下一次任务要运行的时间。当由interval表达式算出next_date是null时,任务自动从任务队列中移出,不会再继续执行。因此,如果传递一个null值给interval参数,则该任务仅仅执行一次。

通过给interval参数赋各种不同的值,可以设计出复杂运行时间计划的任务。本文后面的“任务间隔和日期算法”将对interval表达式进行详细讨论,并给出一个实际有用interval表达式的例子。

四、任务队列架构和运行环境

任务队列在Oracle系统中其实是一个子系统,它具有自己特定的后台过程和目录表。该子系统设计的目的是为了能不在用户干预下自动运行PL/SQL过程。

1、任务队列后台过程

任务队列(SNP)后台过程随着Oracle实例的启动而同时启动。在文章前面已经谈到初始化文件init.ora中的参数JOB_QUEUE_PROCESSES,用来设置有几个队列过程。这里设置了几个过程,系统中就会有几个SNP过程被启动。JOB_QUEUE_PROCESSES这个参数,可以是0到36中的任何一个数,也就是说对于每个Oracle实例最多可以有36个SNP过程,也可以不支持队列过程(=0)。在大多数操作系统中,SNP三个字母常作为过程名的一部分出现。如,在unix系统中,如果该Oracle实例名为ora8,有三个任务队列过程,则这三个任务队列过程名称为:

 

ora_ora8_snp0
ora_ora8_snp1
ora_ora8_snp2

SNP后台过程和其他的Oracle后台过程的一个重要区别就是杀掉一个SNP过程不会影响到Oracle实例。当一个任务队列过程失控或者消耗太多的资源时,就可以将其杀掉,当然这种情况不是经常遇到的。当一个SNP过程被杀掉或者失败时,Oracle就自动启动一个新的SNP过程来代替它。

2、有关任务队列的初始化参数

初始化文件init.ora中的几个参数控制着任务队列后台的运行,下面我们将对其进行详细讨论。

(1)、JOB_QUEUE_INTERVAL

任务队列过程定期唤醒并检查任务队列目录表是否有任务需要执行。参数JOB_QUEUE_INTERVAL决定SNP过程两次检查目录表之间“休眠”多长时间(单位为秒)。间隔设的太小会造成由于SNP过程不断检查目录表而导致不必要的系统吞吐量。相反如果间隔设得太大,SNP过程在特定的时间没有被唤醒,那个时间的任务就不会能被运行。最佳的时间间隔设置要综合考虑系统环境中不同的任务,60秒的确省设置可以满足大多数的应用。

(2)、JOB_QUEUE_KEEP_CONNECTIONS

除了前面介绍的JOB_QUEUE_PROCESS和JOB_QUEUE_INTERVAL两个参数以外,影响SNP后台过程行为的第三个参数是JOB_QUEUE_KEEP_CONNECTIONS。当该参数为TRUE时,SNP过程在两个任务的运行期间(也就是休眠期间),仍然和Oracle保持开放的连接。相反,如果为FALSE时,SNP过程将和数据库断开连接,当唤醒时刻到来时又重新连接并检查任务队列。

选择这两种方法中的那一种,主要是考虑任务队列的有效性和数据库关闭方法。长期保持连接的效率比较高,但任务队列会受到正常关闭数据库的影响。这是因为任务队列过程对于服务器管理器看来和一个普通用户的过程没有什么不同,而正常的关闭数据库需要让所有的用户都断开连接。而断开连接和重新连接又给数据库增加了负荷,但是可定期地使数据库没有可连接SNP过程,也就可以使数据库正常关闭。对于有很多任务或者是任务重复执行的时间间隔较短(一个小时或者更少)的环境,一般将JOB_QUEUE_KEEP_CONNECTIOONS设置为TRUE,并修改关闭数据库的脚本为立即关闭。对于严格要求采用正常方式关闭的数据库或者是任务较少,重复间隔较长的环境,一般将该参数设置为FALSE。最好,要提醒一句,SNP过程仅在没有任何任务运行时才断开,这种情况下,那些需要比较长时间运行的任务SNP将在它们的生命周期内一致保持开放的连接,这就延迟了正常关闭数据库的时间。

3、建立运行环境

当SNP过程唤醒时,它首先查看任务队列目录中所有的任务是否当前的时间超过了下一次运行的日期时间。SNP检测到需要该时间立即执行的任务后,这些任务按照下一次执行日期的顺序依次执行。当SNP过程开始执行一个任务时,其过程如下:

  1. 以任务所有者的用户名开始一个新的数据库会话。
  2. 当任务第一次提交或是最后一次被修改时,更改会话NLS设置和目前就绪的任务相匹配。
  3. 通过interval日期表达式和系统时间,计算下一次执行时间。
  4. 执行任务定义的PL/SQL
  5. 如果运行成功,任务的下一次执行日期(next_date)被更新,否则,失败计数加1。
  6. 经过JOB_QUEUS_INTERVAL秒后,又到了另一个任务的运行时间,重复上面的过程。

在前两步中,SNP过程创建了一个模仿用户运行任务定义的PL/SQL的会话环境。然而,这个模仿的运行环境并不是和用户实际会话环境完全一样,需要注意以下两点:第一,在任务提交时任何可用的非确省角色都将在任务运行环境中不可用。因此,那些想从非确省角色中取得权限的任务不能提交,用户确省角色的修改可以通过在任务未来运行期间动态修改来完成。第二,任何任务定义本身或者过程执行中需要的数据库联接都必须完全满足远程的用户名和密码。SNP过程不能在没有显式指明口令的情况下初始化一个远程会话。显然,SNP过程不能假定将本地用户的口令作为远程运行环境会话设置的一部分。

提交的任务如果运行失败会怎么样呢?当任务运行失败时,SNP过程在1分钟后将再次试图运行该任务。如果这次运行又失败了,下一次尝试将在2分钟后进行,再下一次在4分钟以后。任务队列每次加倍重试间隔直到它超过了正常的运行间隔。在连续16次失败后,任务就被标记为中断的(broken),如果没有用户干预,任务队列将不再重复执行。

五、任务队列字典表和视图

任务队列中的任务信息可以通过表3所示的几个字典视图来查看,这些视图是由CATJOBQ.sql脚本创建的。表4和5是各个视图每个字段的含义。

表3. 任务队列中关于任务的数据字典视图

 

视图名 描述
DBA_JOBS 本数据库中定义到任务队列中的任务
DBA_JOBS_RUNNING 目前正在运行的任务
USER_JOBS 当前用户拥有的任务

表4. DBA_JOBS 和 USER_JOBS.字典视图的字段含义

 

字段(列) 类型 描述
JOB NUMBER 任务的唯一标示号
LOG_USER VARCHAR2(30) 提交任务的用户
PRIV_USER VARCHAR2(30) 赋予任务权限的用户
SCHEMA_USER VARCHAR2(30) 对任务作语法分析的用户模式
LAST_DATE DATE 最后一次成功运行任务的时间
LAST_SEC VARCHAR2(8) 如HH24:MM:SS格式的last_date日期的小时,分钟和秒
THIS_DATE DATE 正在运行任务的开始时间,如果没有运行任务则为null
THIS_SEC VARCHAR2(8) 如HH24:MM:SS格式的this_date日期的小时,分钟和秒
NEXT_DATE DATE 下一次定时运行任务的时间
NEXT_SEC VARCHAR2(8) 如HH24:MM:SS格式的next_date日期的小时,分钟和秒
TOTAL_TIME NUMBER 该任务运行所需要的总时间,单位为秒
BROKEN VARCHAR2(1) 标志参数,Y标示任务中断,以后不会运行
INTERVAL VARCHAR2(200) 用于计算下一运行时间的表达式
FAILURES NUMBER 任务运行连续没有成功的次数
WHAT VARCHAR2(2000) 执行任务的PL/SQL块
CURRENT_SESSION_LABEL RAW MLSLABEL 该任务的信任Oracle会话符
CLEARANCE_HI RAW MLSLABEL 该任务可信任的Oracle最大间隙
CLEARANCE_LO RAW MLSLABEL 该任务可信任的Oracle最小间隙
NLS_ENV VARCHAR2(2000) 任务运行的NLS会话设置
MISC_ENV RAW(32) 任务运行的其他一些会话参数

表 5. 视图DBA_JOBS_RUNNING的字段含义

 

数据类型 描述
SID NUMBER 目前正在运行任务的会话ID
JOB NUMBER 任务的唯一标示符
FAILURES NUMBER 连续不成功执行的累计次数
LAST_DATE DATE 最后一次成功执行的日期
LAST_SEC VARCHAR2(8) 如HH24:MM:SS格式的last_date日期的小时,分钟和秒
THIS_DATE DATE 目前正在运行任务的开始日期
THIS_SEC VARCHAR2(8) 如HH24:MM:SS格式的this_date日期的小时,分钟和秒

六、任务重复运行间隔和间隔设计算法

任务重复运行的时间间隔取决于interval参数中设置的日期表达式。下面就来详细谈谈该如何设置interval参数才能准确满足我们的任务需求。一般来讲,对于一个任务的定时执行,有三种定时要求。

  1. 在一个特定的时间间隔后,重复运行该任务。
  2. 在特定的日期和时间运行任务。
  3. 任务成功完成后,下一次执行应该在一个特定的时间间隔之后。

第一种调度任务需求的日期算法比较简单,即'SYSDATE+n',这里n是一个以天为单位的时间间隔。表6给出了一些这种时间间隔设置的例子。

表6 一些简单的interval参数设置例子

 

描述 Interval参数值
每天运行一次 'SYSDATE + 1'
每小时运行一次 'SYSDATE + 1/24'
每10分钟运行一次 'SYSDATE + 10/(60*24)'
每30秒运行一次 'SYSDATE + 30/(60*24*60)'
每隔一星期运行一次 'SYSDATE + 7'
不再运行该任务并删除它 NULL

表6所示的任务间隔表达式不能保证任务的下一次运行时间在一个特定的日期或者时间,仅仅能够指定一个任务两次运行之间的时间间隔。例如,如果一个任务第一次运行是在凌晨12点,interval指定为'SYSDATE + 1',则该任务将被计划在第二天的凌晨12点执行。但是,如果某用户在下午4点手工(DBMS_JOB.RUN)执行了该任务,那么该任务将被重新定时到第二天的下午4点。还有一个可能的原因是如果数据库关闭或者说任务队列非常的忙以至于任务不能在计划的那个时间点准时执行。在这种情况下,任务将试图尽快运行,也就是说只要数据库一打开或者是任务队列不忙就开始执行,但是这时,运行时间已经从原来的提交时间漂移到了后来真正的运行时间。这种下一次运行时间的不断“漂移”是采用简单时间间隔表达式的典型特征。

第二种调度任务需求相对于第一种就需要更复杂的时间间隔(interval)表达式,表7是一些要求在特定的时间运行任务的interval设置例子。

表 7. 定时到特定日期或时间的任务例子

 

描述 INTERVAL参数值
每天午夜12点 'TRUNC(SYSDATE + 1)'
每天早上8点30分 'TRUNC(SYSDATE + 1) + (8*60+30)/(24*60)'
每星期二中午12点 'NEXT_DAY(TRUNC(SYSDATE ), ''TUESDAY'' ) + 12/24'
每个月第一天的午夜12点 'TRUNC(LAST_DAY(SYSDATE ) + 1)'
每个季度最后一天的晚上11点 'TRUNC(ADD_MONTHS(SYSDATE + 2/24, 3 ), 'Q' ) -1/24'
每星期六和日早上6点10分 'TRUNC(LEAST(NEXT_DAY(SYSDATE, ''SATURDAY"), NEXT_DAY(SYSDATE, "SUNDAY"))) + (6×60+10)/(24×60)'

第三种调度任务需求无论通过怎样设置interval日期表达式也不能满足要求。这时因为一个任务的下一次运行时间在任务开始时才计算,而在此时是不知道任务在何时结束的。遇到这种情况怎么办呢?当然办法肯定是有的,我们可以通过为任务队列写过程的办法来实现。这里我只是简单介绍以下,可以在前一个任务队列执行的过程中,取得任务完成的系统时间,然后加上指定的时间间隔,拿这个时间来控制下一个要执行的任务。这里有一个前提条件,就是目前运行的任务本身必须要严格遵守自己的时间计划。

结论

Oracle中的定时任务是在Oracle系统中是一个非常重要的子系统,运用得当,可以极大的提高我们的系统运行和维护能力。而Oracle数据复制的延迟事务队列管理完全是基于Oracle的队列任务,对其的深刻理解有助于我们更好地管理数据复制。


posted @ 2009-08-26 10:30 鸿雁 阅读(438) | 评论 (0)编辑 收藏

IText使用PDF模板输出报表的实践(转)

本文所要用到的工具或jar主要有: Acrobat 8 这个主要用来制作PDF模板、eclipse这个看你喜欢咯(你用其他也行) 、 itext.jar、
还有为了解决中文的输出问题,需要多下载一个名为iTextAsian.jar的JAR包。这个包里面定义了与中文输出相关的一些文件。
好了,需要做的就是这些了,简单的PDF生成这里就不再作介绍了,本文主要讲解如何使用PDF模板。
我们先来看看制作出来的效果:


上图表格上及表格中的数据是动态添加进去的,页数为两页(为节约版面现只显示一页)
两页都是用的同一模板的,
1、 模板的制作:
我主要使用的是Acrobat8.0,上面所用到的模板是由 周工作报告 模板修改而来的,如果想学习如何新建一个新的模板,大家可以参照下这里吧!
http://lxy19791111.javaeye.com/blog/102848
2、 取得每个表单域的名字
模板制作好后,要插入数据首先就要知道需要插在模板中位置,
Java代码 复制代码
  1.   //需要生成后的PDF    
  2. FileOutputStream fos = new FileOutputStream("c:/test/Pdf.pdf");    
  3.   //PDF模板路径    
  4. String TemplatePDF ="c:/test/PdfTemplate.pdf";    
  5.        PdfReader reader = new PdfReader(TemplatePDF);      
  6. PdfStamper stamp = new PdfStamper(reader,fos);    
  7. AcroFields form = stamp.getAcroFields();    
  8. for (Iterator it = form.getFields().keySet().iterator(); it    
  9. .hasNext();) {    
  10. System.out.println(it.next());    
  11. }   

这个是打印后的部分结果:

我们只取后面那个命名就行,如"星期四[3]"
当然,模板是你自己定义,文本域的命名你当然知道了,这里只是作个简单介绍而已。
3、下面是插入数据及PDF合并的代码:
Java代码 复制代码
  1. package com.golden.info.test;   
  2.   
  3. import java.io.ByteArrayOutputStream;   
  4. import java.io.FileNotFoundException;   
  5. import java.io.FileOutputStream;   
  6. import java.io.IOException;   
  7. import java.util.Date;   
  8.   
  9. import com.lowagie.text.Document;   
  10. import com.lowagie.text.DocumentException;   
  11. import com.lowagie.text.pdf.AcroFields;   
  12. import com.lowagie.text.pdf.PdfCopy;   
  13. import com.lowagie.text.pdf.PdfImportedPage;   
  14. import com.lowagie.text.pdf.PdfReader;   
  15. import com.lowagie.text.pdf.PdfStamper;   
  16. public class TestPdfTemplate {     
  17.     public static void main(String[] args) {   
  18.         try {   
  19.             int count = 8;// 总记录数   
  20.             int pageCount = 4;// 每页记录数   
  21.             int index = 1// 表格序号   
  22.             int page = 0;// 总共页数   
  23.             /** 主要控制总共的页数*/  
  24.             if (count >= pageCount && count % pageCount == 0) {   
  25.                 page = count / pageCount;   
  26.             } else {   
  27.                 page = count / pageCount + 1;   
  28.             }   
  29.             String TemplatePDF = "c:/test/PdfTemplate.pdf";//设置模板路径   
  30.             FileOutputStream fos = new FileOutputStream("c:/test/Pdf.pdf");//需要生成PDF   
  31.                
  32.             ByteArrayOutputStream baos[] = new ByteArrayOutputStream[page];//用于存储每页生成PDF流   
  33.             /** 向PDF模板中插入数据 */  
  34.             for (int item = 0; item < page; item++) {   
  35.                 baos[item] = new ByteArrayOutputStream();   
  36.                 PdfReader reader = new PdfReader(TemplatePDF);   
  37.                 PdfStamper stamp = new PdfStamper(reader, baos[item]);   
  38.                 AcroFields form = stamp.getAcroFields();   
  39.                 form.setField("DepartmnetNmae""蓝飞");//插入的数据都为字符类型   
  40.                 form.setField("qq""252462807");                  
  41.                 form.setField("pageNumber""第" + (item + 1) + "页,共" + page   
  42.                         + "页");   
  43.                 if (count % pageCount != 0 && item == page - 1) {   
  44.                     System.out.println("====pageCount+" + pageCount + "=====");   
  45.                     pageCount = count % pageCount;   
  46.                 }   
  47.                 /**因为PDF中的表格其实是众多的文本域组成,就是一个数组,所以把它循环出来就可以了*/  
  48.                 for (int j = 0; j < pageCount; j++) {   
  49.                     form.setField("ProjectTask[" + j + "]", index + "");   
  50.                     form.setField("星期一[" + j + "]""星期一[" + index + "]");   
  51.                     form.setField("星期二[" + j + "]""星期二[" + index + "]");   
  52.                     form.setField("星期三[" + j + "]""星期三[" + index + "]");   
  53.                     form.setField("星期四[" + j + "]""星期四[" + index + "]");   
  54.                     form.setField("星期五[" + j + "]""星期五[" + index + "]");   
  55.                     form.setField("星期六[" + j + "]""星期六[" + index + "]");   
  56.                     form.setField("星期日[" + j + "]""星期日[" + index + "]");   
  57.                     form.setField("意见[" + j + "]""同意[" + j + "]");   
  58.                     index++;   
  59.                 }   
  60.                 stamp.setFormFlattening(true); // 千万不漏了这句啊, */   
  61.                 stamp.close();   
  62.             }   
  63.             Document doc = new Document();   
  64.             PdfCopy pdfCopy = new PdfCopy(doc, fos);   
  65.             doc.open();   
  66.             PdfImportedPage impPage = null;   
  67.             /**取出之前保存的每页内容*/  
  68.             for (int i = 0; i < page; i++) {   
  69.                 impPage = pdfCopy.getImportedPage(new PdfReader(baos[i]   
  70.                         .toByteArray()), 1);   
  71.                 pdfCopy.addPage(impPage);   
  72.             }   
  73.             doc.close();//当文件拷贝  记得关闭doc   
  74.         } catch (FileNotFoundException e) {   
  75.             e.printStackTrace();   
  76.         } catch (IOException e) {   
  77.             e.printStackTrace();   
  78.         } catch (DocumentException e) {   
  79.             e.printStackTrace();   
  80.         }   
  81.   
  82.     }   
  83. }  


至于,生于PDF后,想打印出来,只要调用以下代码就行了
Java代码 复制代码
  1.            
  2. try{                
  3. Executable ex = new Executable();          
  4.        ex.openDocument("c:/test/Pdf.pdf");              
  5.     ex.printDocument("c:/test/Pdf.pdf");   
  6.     }catch(IOException e){       
  7.     e.printStackTrace();         
  8.     }  

到这里,运用上面的那些代码,就完成了PDF模板输出报表.
(PDF模板、代码跟运行结果在附件里)
有错误之处请指正.
也希望这篇文章可以帮到您.

posted @ 2009-08-12 09:53 鸿雁 阅读(4503) | 评论 (0)编辑 收藏

利用 iText 实现 PDF 报表下载 (转)

     摘要: 有个朋友的项目需要用到 PDF 报表下载,之前我只做过 Excel 的,相信再做一次 PDF 的下载一定很有趣吧。在网上找了一大圈,似乎 iText 比较符合我的要求,而且这个工具很早很早以前就有了,生命力很旺盛。进入 iText 的主页(http://www.lowagie.com/iText/),发现作者很勤劳,最近2个月都有新版本发布。哪知道现在高兴得太早了,一堆问题接踵而至。 下载倒...  阅读全文

posted @ 2009-08-12 09:50 鸿雁 阅读(417) | 评论 (0)编辑 收藏

iText JSP中生成PDF(入门)

iText简介

  iText是一个开放源码的Java类库,可以用来方便地生成PDF文件。大家通过访问http://sourceforge.net/project/showfiles.php?group_id=15255&release_id=167948下载最新版本的类库,下载完成之后会得到一个.jar包,把这个包加入JDK的classpath即可使用。如果生成的PDF文件中需要出现中文、日文、韩文字符,则还需要通过访问http://itext.sourceforge.net/downloads/iTextAsian.jar下载iTextAsian.jar包。

  关于iText类库的使用,http://www.lowagie.com/iText/tutorial/index.html有比较详细的教程。该教程从入门开始,比较系统地介绍了在PDF文件中放入文字、图片、表格等的方法和技巧。读完这片教程,大致就可以做一些从简单到复杂的PDF文件了。不过,试图通过教程解决在生成PDF文件过程中遇到的所有困难无疑是一种奢望。所以,阅读iText的api文档显得非常重要。读者在下载类库的同时,也可以下载类库的文档。

可参考资料 :  

http://dev.csdn.net/article/62/62119.shtm       http://myowndream.blog.com.cn/archives/2007/2089386.shtml
http://tag.csdn.net/tag/itext.xml

一  HelloWorld实例

以下是上述教程中一个最简单的例子,这个例子刻画了通过iText生成PDF文件的一般程序框架。读者只需要在document.open();和document.close();两条语句中间加入自己希望放在PDF文件中的内容即可。该例子只在PDF文件中加了“Hello World“一行文字。

Document document = new Document();

try{
    PdfWriter.getInstance(document, new FileOutputStream ("Chap0101.pdf"));

    document.open();

    document.add(new Paragraph("Hello World"));
}catch(DocumentException de){
     System.err.println(de.getMessage());
}catch(IOException ioe){
     System.err.println(ioe.getMessage());
}
 
document.close();

可以看到一个PDF文件的输出,总共只需要5个步骤
a.创建一个Document实例
  Document document = new Document();
b.将Document实例和文件输出流用PdfWriter类绑定在一起
  PdfWriter.getInstance(document,new FileOutputStream("HelloWorld.pdf"));
c.打开文档
  document.open();
d.在文档中添加文字
  document.add(new Paragraph("Hello World"));
e.关闭文档
  document.close();
这样5个步骤,就可以生成一个PDF文档了。

然而在PDF中指定文字、图画、表格的位置是一件非常麻烦的事情。除了不断地在程序中修改位置、然后运行程序、生成PDF文件、观察元素在PDF中的位置是否合理这样的过程以外,似乎还没有其它更好的方法。

二。如何使用jsp、servlet输出iText生成的pdf?
   如果每次都在服务端生成一个PDF文件给用户,不仅麻烦,而且浪费服务器资源,最好的方法就是以二进制流的形式输送到客户端。
1)JSP输出:

<%@ page import="java.io.*,java.awt.Color,com.lowagie.text.*,com.lowagie.text.pdf.*"%>
<%
 response.setContentType( "application/pdf" );
 Document document = new Document();
 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
 PdfWriter writer=PdfWriter.getInstance( document, buffer );

 document.open();

 document.add(new Paragraph("Hello World"));

 document.close();

 DataOutput output = new DataOutputStream( response.getOutputStream() );
 byte[] bytes = buffer.toByteArray();
 response.setContentLength(bytes.length);
 for( int i = 0; i < bytes.length; i++ ){
  output.writeByte( bytes[i] );
 }

%>

2)servlet输出,稍微改造下就可以使用在struts中:

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException,ServletException{

  Document document = new Document(PageSize.A4, 36,36,36,36);
  ByteArrayOutputStream ba = new ByteArrayOutputStream();

  try{
   PdfWriter writer = PdfWriter.getInstance(document, ba);

   document.open();

   document.add(new Paragraph("Hello World"));
  }catch(DocumentException de){
   de.printStackTrace();
   System.err.println("A Document error:" +de.getMessage());
    }

  document.close();

  response.setContentType("application/pdf");
  response.setContentLength(ba.size());
  ServletOutputStream out = response.getOutputStream();
  ba.writeTo(out);
  out.flush();
}

三。如何输出中文?
     首先需要下载iTextAsian.jar包,可以到iText的主站上下,ireport也是需要这个包的。然后定义中文字体:

    private static final Font getChineseFont() {
         Font FontChinese
= null;
        
try {
             BaseFont bfChinese
= BaseFont.createFont("STSong-Light",
                    
"UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
             FontChinese
= new Font(bfChinese, 12, Font.NORMAL);
         }
catch (DocumentException de) {
             System.err.println(de.getMessage());
         }
catch (IOException ioe) {
             System.err.println(ioe.getMessage());
         }
        
return FontChinese;
     }


我将产生中文字体封装在方法内,自定义一个段落PDFParagraph继承自Paragraph,默认使用中文字体:

class PDFParagraph extends Paragraph {
        
public PDFParagraph(String content) {
            
super(content, getChineseFont());
         }
     }


使用的时候就可以简化了:

Paragraph par = new PDFParagraph("你好");


四。如何设置PDF横向显示和打印?

Rectangle rectPageSize = new Rectangle(PageSize.A4);// 定义A4页面大小
rectPageSize = rectPageSize.rotate();// 加上这句可以实现A4页面的横置
Document doc = new Document(rectPageSize,50,50,50,50);//4个参数,设置了页面的4个边距


五。如何设置跨行和跨列?

使用PdfPTable和PdfPCell 是没办法实现跨行的,只能跨列,要跨行使用com.lowagie.text.Table和com.lowagie.text.Cell类,Cell类有两个方法:setRowspan()和setColspan()。

六。如何设置单元格边界宽度?

Cell类的系列setBorderWidthXXXX()方法,比如setBorderWidthTop(),setBorderWidthRight()等

七。如何设置表头?
希望每一页都有表头,可以通过设置表头来实现。对于PdfPTable类来说,可以这样设置:

PdfPTable table = new PdfPTable(3);
table.setHeaderRows(
2); // 设置了头两行为表格头


而对于om.lowagie.text.Table类,需要在添加完所有表头的单元格后加上一句代码:

table.endHeaders();


八。如何设置列宽?

Table table = new Table(8);
float[] widths = { 0.10f, 0.15f, 0.21f, 0.22f, 0.08f, 0.08f, 0.10f,
                    
0.06f };
table.setWidths(widths);


上面的代码设置了一个有8列的表格,通过一个float数组设置列宽,这里是百分比。

九。单元格内段落文字居中和换行?
居中通过Cell类来设置,一开始我以为设置段落对齐就可以了,没想到是需要设置单元格:

cell.setHorizontalAlignment(Element.ALIGN_CENTER);



转义符\n实现。在我的这个应用中,因为数据库取出的数据是为了显示在html上的,所以有很多<br>标签,可以使用正则表达式替换成"\n"

"<br>1.测试<br>2.测试2".replaceAll("<br>|</br>","\n");


十。如何显示页码?
复杂的页码显示和水印添加,需要使用到PdfPageEventHelper、PdfTemplate等辅助类,具体的例子参见iText的文档,如果只是为了简单的显示页数,可以使用下面的代码:

             HeaderFooter footer = new HeaderFooter(new Phrase("页码:",getChineseFont()), true);
             footer.setBorder(Rectangle.NO_BORDER);
             document.setFooter(footer);
             document.open();

你可能注意到了,添加footer需要在document.open之前。

posted @ 2009-08-12 09:48 鸿雁 阅读(2327) | 评论 (0)编辑 收藏

开发相关的重点技术介绍-转贴

     摘要: 数据库连接池的原理机制 数据库连接池的原理机制 ...  阅读全文

posted @ 2009-05-15 10:32 鸿雁 阅读(1356) | 评论 (0)编辑 收藏

仅列出标题
共18页: First 上一页 4 5 6 7 8 9 10 11 12 下一页 Last