<<上篇 | 首页 | 下篇>>

Javascript Best Practices

 

Introduction

This document is a list of best practices and preferred ways of developing javascript code, based on opinions and experience from many developers in the javascript community. Since this is a list of recommendations rather than a list of absolute rules, experienced developers may have slightly differing opinions from those expressed below.


Table Of Contents

  1. Always Use 'var'
  2. Feature-Detect Rather Than Browser-Detect
  3. Use Square Bracket Notation
  4. Avoid 'eval'
  5. Reference Forms and Form Elements Correctly
  6. Avoid 'with' Statements
  7. Use onclick In Anchors Instead Of javascript: Pseudo-Protocol
  8. Use The Unary + Operator To TypeConvert To Number
  9. Avoid document.all
  10. Don't Use HTML Comments In Script Blocks
  11. Avoid Cluttering The Global Namespace
  12. Avoid sync "Ajax" calls
  13. Use JSON
  14. Use Correct <script> Tags

阅读全文……

标签 :

Spring, JdbcTemplate and Transactions

JdbcTemplate的事务问题

使用Spring的JdbcTemplate,必须传入DataSource对象构造JdbcTemplate,JdbcTemplate使用的Connection对象是一个新申请的,而且JdbcTemplate操作采用的是JDBC默认的AutoCommit模式,因此如果同时在一个DAO或者Service里混合用了HibernateTemplate和JdbcTemplate,甚至默认的配置情况下,使用同一个JdbcTemplate两次操作SQL也不是事务的。要让JdbcTemplate单独支持事务必须做一些编码或特殊的配置:

  

Yet another item in my dirty-secrets category is the fact that so far, until about a week ago, I had never used database transactions withSpring and JDBC, although I have been using Spring for more than 3 years now. Before Spring, I did a lot of classic JDBC coding with the try..catch..finally pattern. My first application using Spring was to wrap another third party application which updated its MySQLdatabases using JDBC as well. In a few instances we would add hooks to insert/update additional data using JDBC. Subsequently I discovered JdbcTemplate, but I was now working on applications where the main focus was transaction speeds and it was acceptable to lose a few records here and there, so we used MySQL with the MyISAM storage engine (which does not support transactions) was chosen. To the readers who are cringing in horror, I am happy to report that we only had about half an hour of downtime in about 3 years of operation because of data corruption, and that half hour included figuring out why our servers were hung and switching to the replication server.

At my current job, we are using Spring with Oracle. So far I did not have to use transactions in my Spring JDBC code. There is a lot of code written in classic JDBC (using transactions) in the application, and most of the work I had done so far was reading that data, which did not need transactions. However, sometime early last week, I had to write the Data Access Object for a bean which consisted of one parent table and three child tables with foreign key dependencies on the parent. The save() and delete() methods of this DAO needed to be transactional since all the JDBC operations needed to succeed or fail as a unit.

I have used transactions with Spring and Hibernate in a small project (also on MySQL, but with the InnoDb storage engine) before. However, since Spring-Hibernate usage is so widely documented on the web, the effort did not involve much understanding. Spring-JDBC usage gets significantly less coverage, perhaps because it is not as popular. I began by applying the prescriptive examples I found on the web, but no matter what I tried, Oracle would complain about missing foreign keys and throw an exception. It ultimately turned out to be an application bug, but the problem led me to read up on transactions, and look at Spring code and find out how the TransactionTemplate is implemented, etc, so happily, I now understand a little more about Spring and J2EE transactions than I did before.

Setting up the Transaction Manager

No matter what approach (Declarative or Programmatic) you take with making your Spring-JDBC code transactional, you will need aTransaction Manager. Spring provides a DataSourceTransactionManager which you can use if your application speaks to a single database, otherwise you may need to choose the appropriate JTA Transaction Manager implementation. Regardless, switching out theTransaction Manager just involves changing the bean definition below. Here is the definition:

1
2
3
4
5
6
7
8
9
  <!-- you should already have one of these -->
  <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    ...
  </bean>

  <!-- this should be added for transaction support -->
  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource"/>
  </bean>

The Programmatic Approach

My initial implementation was using the programmatic transaction approach using a TransactionTemplate to wrap the code that needs to be in a transaction. To do this, my DAO bean declared a dependency on the TransactionManager bean defined above.

1
2
3
4
  <bean id="myDao" class="com.mycompany.daos.MyDao">
    <property name="dataSource" ref="dataSource"/>
    <property name="transactionManager" ref="transactionManager"/>
  </bean>

Our DAO code has methods to select various attributes based on various input parameters (named getXXX() and findXXX() by convention) and a save() and delete() method that inserts and deletes the bean from the database. The additional things a transactional DAO must have is the reference and setter for the Transaction Manager, code to build a Transaction Template from the Transaction Manager, and a TransactionCallback to wrap the transactional bit of code. This is shown below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class MyDao extends JdbcDaoSupport {

  private TransactionTemplate txTemplate;
  ...

  public void setTransactionManager(PlatformTransactionManager txManager) {
    this.txTemplate = new TransactionTemplate(txManager);
    this.txTemplate.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED);
  }

  ...
  public int save(MyBean bean) throws Exception {
    final int savedBeanId = (beanId == 0 ? getNextBeanId() : beanId);
    txTemplate.execute(new TransactionCallbackWithoutResult() {
      public void doInTransactionWithoutResult(TransactionStatus status) {
        if (beanId == 0) {
          getJdbcTemplate().update("insert into beans(id,name) values (?,?)",
            new Object[] {savedBeanId, bean.getName()});
        } else {
          getJdbcTemplate().update("update partner set name=? where id=?",
            new Object[] {bean.getName(), savedBeanId});
        }
        for (String beanProp1 : bean.getProps1()) {
          getJdbcTemplate().update(
            "insert into bean_props1(bean_id,prop_value) values (?,?)",
             new Object[] {savedBeanId, beanProp1});
        }
        for (String beanProp2 : bean.getProps2()) {
          getJdbcTemplate().update(
            "insert into bean_props2(bean_id,prop_value) values (?,?)",
             new Object[] {savedBeanId, beanProp2});
        }
        for (String beanProp3 : bean.getProps3()) {
          getJdbcTemplate().update(
            "insert into bean_props3(bean_id,prop_value) values (?,?)",
            new Object[] {savedBeanId, beanProp3});
        }
      }
    });
    return savedBeanId;
  }
  ...
}

Note that I did not want to return anything from my TransactionCallback, so I used a TransactionCallbackWithoutResult object. If there is a need to pass a result back from the callback, you can use TransactionCallback instead.

The Declarative Approach

Spring and most authors recommend using the Declarative approach. With this approach, the DAO code has no reference to the TransactionTemplate. It is identical to a DAO which would have been written to work without transactions. The DAO itself is wrapped inside a TransactionProxyFactoryBean which provides the transactional behavior for the bean. The transactional behavior can be configured in the application context using XML. Our configuration to make the save() and delete() methods work within a transaction but leave the getXXX() methods alone would look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
  <bean id="myDaoTarget" class="com.mycompany.daos.MyDao">
    <property name="dataSource" ref="dataSource"/>
  </bean>

  <bean id="myDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="target" ref="myDaoTarget"/>
    <property name="proxyTargetClass" value="true"/>
    <property name="transactionAttributes">
      <props>
        <prop key="*">PROPAGATION_REQUIRED,-Exception</prop>
        <prop key="get*">PROPAGATION_SUPPORTS</prop>
      </props>
    </property>
  </bean>

I used CGLIB proxying because I did not want to define an interface for MyDao, but if an interface was defined, I could have used standard Java interface based proxying as well. The resulting DAO code now looks identical to one without transactions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MyDao extends JdbcDaoSupport {
  ...
  public int save(MyBean bean) throws Exception {
    final int savedBeanId = (beanId == 0 ? getNextBeanId() : beanId);
    if (beanId == 0) {
      getJdbcTemplate().update("insert into beans(id,name) values (?,?)",
        new Object[] {savedBeanId, bean.getName()});
    } else {
      getJdbcTemplate().update("update partner set name=? where id=?",
        new Object[] {bean.getName(), savedBeanId});
    }
    for (String beanProp1 : bean.getProps1()) {
      getJdbcTemplate().update(
        "insert into bean_props1(bean_id,prop_value) values (?,?)",
        new Object[] {savedBeanId, beanProp1});
    }
    for (String beanProp2 : bean.getProps2()) {
      getJdbcTemplate().update(
        "insert into bean_props2(bean_id,prop_value) values (?,?)",
         new Object[] {savedBeanId, beanProp2});
    }
    for (String beanProp3 : bean.getProps3()) {
      getJdbcTemplate().update(
        "insert into bean_props3(bean_id,prop_value) values (?,?)",
        new Object[] {savedBeanId, beanProp3});
    }
    return savedBeanId;
  }
  ...
}

或者:

public void insert(){ 
JdbcTempalte jt=new JdbcTemplate(dataSource); 
jt.update(1); 
jt.update(2); 
} 

For both the transaction and declarative approaches, note that it is not necessary to have all the JDBC code in a single method. If we wanted to refactor our save() code into multiple doSaveMyBeanMain(), doSaveMyBeanProps1(), etc, methods, using either of the above approaches without any modification will retain the transactional behavior.

Conclusion

This post described two approaches to making the DAO transactional with Spring and JDBC. The approaches described here are not new, they are based on approaches detailed in Spring documentation and other web pages, but I do it in more of a prescriptive style, and in more detail. Hopefully, it will be helpful to people using transactions with JDBC and Spring.

References

The following documents helped me to understand transactions and how they are used within Spring and EJB3.

标签 : , , ,

DOM 的有效使用

DOM的有效使用

考虑到由 DOM 设计强加的限制,如何才能有效和高效的使用该规范呢?下面是使用 DOM 的几条基本原则和方针,以及使工作更方便的函数库。

基本原则

如果您遵循几条基本原则,您使用 DOM 的经验将会显著提高:

  • 不要使用 DOM 遍历文档。
  • 尽可能使用 XPath 来查找节点或遍历文档。
  • 使用较高级的函数库来更方便地使用 DOM。

这些原则直接从对常见问题的研究中得到。正如上面所讨论的,DOM 遍历是出错的主要原因。但它也是最常需要的功能之一。如何通过不使用 DOM 而遍历文档呢?

Path

XPath 是寻址、搜索和匹配文档的各个部分的语言。它是 W3C 推荐标准(Recommendation),并且在大多数语言和 XML 包中实现。您的 DOM 包可能直接支持 XPath 或通过加载件(add-on)支持。本文的样本代码对于 XPath 支持使用 Xalan 包。

XPath 使用路径标记法来指定和匹配文档的各个部分,该标记法与文件系统和 URL 中使用的类似。例如,XPath: /x/y/z 搜索文档的根节点 x ,其下存在节点 y ,其下存在节点 z 。该语句返回与指定路径结构匹配的所有节点。

更为复杂的匹配可能同时在包含文档的结构方面以及在节点及其属性的值中。语句 /x/y/* 返回父节点为 x  y 节点下的任何节点。 /x/y[@name='a'] 匹配所有父节点为 x  y 节点,其属性称为 name ,属性值为 a 。请注意,XPath 处理筛选空格文本节点以获得实际的元素节点 ― 它只返回元素节点。

详细探讨 XPath 及其用法超出了本文的范围。请参阅 参考资料获得一些优秀教程的链接。花点时间学习 XPath,您将会更方便的处处理 XML 文档。

DOM 的语言无关性设计为其带来了非常广泛的可应用性并使其在大量的系统和平台上得以实现。这样做的代价是:使 DOM 比为每个语言专门设计的 API 更困难且更缺乏直观性。

DOM 奠定了一个非常有效的基础,遵循一些简单的原则就可其上构建易于使用的系统。凝结了一大群用户智慧和经验的 DOM 未来版本正在设计之中,而且极有可能为这里讨论的问题提供解决方案。如 JDOM 这样的项目正在修改该 API 以获得更自然 Java 感觉,而且如本文中所述的技术可以帮助您使 XML 的操纵更方便、更简洁并且不易出错。利用这些项目且遵循这些用法模式以允许 DOM 成为基于 XML 项目的出色平台。

DOM解析XML、修改Node的属性:

package com.lph.html;

import java.io.*;
import java.util.*;
import org.w3c.dom.*;
import javax.xml.parsers.*;

public class TestDom {
 public static void main(String arge[]) {
  long lasting = System.currentTimeMillis();
  try {
   File f = new File("D:/data_10k.xml");
   DocumentBuilderFactory factory = DocumentBuilderFactory
     .newInstance();
   DocumentBuilder builder = factory.newDocumentBuilder();
   Document doc = builder.parse(f);
   NodeList nl = doc.getElementsByTagName("VALUE");
   for (int i = 0; i < nl.getLength(); i++) {
    Node node=nl.item(i);
    node.getAttributes().getNamedItem("name").setNodeValue("www");
    
    System.out.print("车牌号码:"
      + doc.getElementsByTagName("NO").item(i)
        .getFirstChild().getNodeValue());
    System.out.println("车主地址:"
      + doc.getElementsByTagName("ADDR").item(i)
        .getFirstChild().getNodeValue());
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

 

 

标签 : ,