东东东 陈煜东的博客

分类存档: Java ( 1 / 2)

在java学习中的文章

Hibernate session在service实现事务,getCurrentSession()和openSession()区别

当我们在使用Hibernate作为数据库操作的类库时,我们一般在DAO层里与数据库相关的操作,把业务逻辑写在service层里。但是如果我们的项目比较小,那么直接在dao层里写事务也是可以的,这个就是看个人了,没有什么特别的规定。但是如果项目比较大,那么DAO应该只做单纯的数据库的操作,service写事务的操作,即整个业务逻辑。

例如:业务逻辑要求向数据库中的用户表增加一个用户,同时向日志表中加入一条日志,而这需要调用DAO的两个方法(UserDao的saveUser和LogDao的saveLog)。这显然是一个事务,也就是如果一个操作出现了问题,就要回滚到初始的状态。那么如何在Service层控制事务呢,本文就以此例的代码说明。

在DAO进行Session事务出现的问题

我们先看看在DAO层里写Hibernate的session的事务。

package com.xxg;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();
    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

创建用户表T_user(id,username)和日志表T_log(id,content),以及它们对应的实体类User、Log及映射文件,这里就不一一贴出代码。

public class UserDao {

    public void saveUser(User user){
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory
        Session session = sessionFactory.openSession();// openSession
        session.beginTransaction(); //开始事务

        session.save(user);

        session.getTransaction().commit(); //事务提交
        session.close(); //关闭session
    }
}
public class LogDao {

    public void saveLog(Log log){
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory
        Session session = sessionFactory.openSession();// openSession
        session.beginTransaction(); //开始事务

        session.save(log);

        session.getTransaction().commit(); //事务提交
        session.close(); //关闭session
    }

}

接下来我们看看在service中写一个业务逻辑

public class TestService {

    public void save(User user){
        UserDao userDao = new UserDao();
        userDao.saveUser(user);

        LogDao logDao = new LogDao();
        Log log = new Log();
        log.setContent("插入一个用户");
        logDao.saveLog(log);
    }

}

可以看到,我们在两个DAO里写了数据库的事务,代码中高亮显示了,session.beginTransaction()显示声明事务的开始。

这样写是不对的,因为这两个事情作为一个事务来进行的,会出现一个事务成功提交,而另外一个可能提交失败,导致不一致的情况,这样这两个操作不算是一个事务transaction,所以这么写就是一个失败的事务。

因此,我们要将事务在service中进行声明。

在service层写session的数据库事务

为了将事务放在service中,我们需要更改HibernateUtil的代码才能实现。否则使用上面的那个不能达到我们的需求。在这个新的HibernateUtil代码中,利用了ThreadLocal的线程内的局部变量来保存hibernate的session对象。这样就可以在不同的class中使用同一个session对象,而不用传递参数。

public class HibernateUtil {
    public static final ThreadLocal session = new ThreadLocal();

    public static final SessionFactory sessionFactory;
    static {
        try {
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch ( Throwable ex ) {
            throw new ExceptionInInitializerError( ex );
        }
    }

    public static Session currentSession() throws HibernateException
    {
        Session s = session.get();
        if ( s == null )
        {
            s = sessionFactory.openSession();
            session.set( s );
        }
        return(s);
    }

    public static void closeSession() throws HibernateException
    {
        Session s = session.get();
        if ( s != null )
        {
            s.close();
        }
        session.set( null );
    }
}

接下来,我们将事务放在service中。看代码:

public class TestService {

    public void save(User user){

        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory
        Session session = sessionFactory.getCurrentSession();//getCurrentSession
        session.beginTransaction();//事务开始

        UserDao userDao = new UserDao();
        userDao.saveUser(user);

        LogDao logDao = new LogDao();
        Log log = new Log();
        log.setContent("插入一个用户");
        logDao.saveLog(log);
        session.getTransaction().commit();//事务提交
    }

}

 

public class LogDao {

    public void saveLog(Log log) throws RuntimeException{
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory
        Session session = sessionFactory.getCurrentSession(); //getCurrentSession

        session.save(log);

        throw new RuntimeException();
    }
}

 

public class UserDao {

    public void saveUser(User user){
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory
        Session session = sessionFactory.getCurrentSession();//getCurrentSession

        session.save(user);

    }

}

通过getCurrentSession()可以获得当前线程的session对象,通过它来进行共享session。这样事务就从service开始,然后再service结束。

getCurrentSession()与openSession()区别

getCurrentSession创建的session会和绑定到当前线程,而openSession不会。

getCurrentSession创建的线程会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭

采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession() 创建的session则不会 * 采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession() 创建的session必须手动关闭

2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:

  • 如果使用的是本地事务(jdbc事务) <property name=”hibernate.current_session_context_class”>thread</property>
  • 如果使用的是全局事务(jta事务) <property name=”hibernate.current_session_context_class”>jta</property>

getCurrentSession()与openSession()关联

在 SessionFactory 启动的时候, Hibernate 会根据配置创建相应的 CurrentSessionContext ,在 getCurrentSession() 被调用的时候,实际被执行的方法是 CurrentSessionContext.currentSession() 。在 currentSession() 执行时,如果当前 Session 为空, currentSession 会调用 SessionFactory 的 openSession 。所以 getCurrentSession() 对于 Java EE 来说是更好的获取 Session 的方法。

参考资料

  • http://blog.csdn.net/xiao__gui/article/details/7695698
  • http://blog.csdn.net/loveyout/article/details/4193894

分类: JavaEE

Java Interface声明成员变量应该要注意的东西

Java中的Interface是声明一个接口类型。而实现这个接口的类需要实现它的方法。外界可以通过多态行为来进行调用。但是一般很少在interface中定义成员变量。

public interface Interface{
    int width =10;
}

在Interface中声明成员变量width,那么在外部的类是可以直接调用这个变量的。外界只要使用I.width就可以调用了。

我们可以看到,在声明中,我们没有添加public static的关键字,但是Java在编译完成后,会将Interface中的成员变量自动使用public static final关键字来修饰。而方法会使用public关键字来修饰。

所以大家在声明Interface中要注意以下,虽然可以省略,但是最好还是添加上,这样一看就很直观,不会造成不良的影响。

分类: Java

Java Singleton 单例模式

在设计模式中,单例模式(Singleton)是最长见得一种设计模式之一。什么是单例模式呢?就是在整个系统中,只有一个唯一存在的实例。这样的情况可以干什么用呢?比如可以统计网站的访问量,一些连接池(数据库连接池等)。

一个最简单的单例模式 – 饿汉模式

那么怎么能保证只有一个对象的存在呢?首先得有一个static的实例,这个方法保证了一个class只有一个实例。还得防止外界使用构造器来new一个实例。

//一个没有封装的单例模式
public class Singleton {
    public static final Singleton singleton = new Singleton();
    private Singleton(){}
}

外界就可以使用Singleton.singleton这样的方法来调用了。但是这样存在的问题就是分装不够好,添加一个方法,返回singleton的引用。如下

//最简单的封装单例改进版。饿汉模式
public class Singleton {
    public static final Singleton singleton = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){ return singleton; }
}

当代码写到这,我们终于可以松一口气了,原来单例模式也很简单呀,就这么几行的代码。对,其实这个是最简单的一种方式,能够应付大部分的场景的。

不过,其他class在引用Singleton而不使用的时候,虚拟机会自动加载这个类,并且实例化这个对象(这点知道Java虚拟机的类加载就会了解那么一些)。于是我们就有了下面的写法。

延迟实例化(懒汉模式) – 在调用时进行实例化

经常能看见其他的单例模式会教下面的代码,这样的人估计是从《设计模式 – 可复用面向对象软件的基础》那本书看来的。这本书使用的是C++语言写的,然后就将其转到了Java平台来。

首先他们会说我们的代码应该先这样,在调用的时候,发现为null,再进行实例化该类。

public class Singleton {
    public static final Singleton singleton = null;
    private Singleton(){}
    public static Singleton getInstance(){
        if(singleton == null){ //如果singleton为空,表明未实例化
           singleton = new Singleton();
        }
        return singleton;
    }
}

然后他们还会说,这样在多线程的情况下会出现这样的情况:两个进程都进入到if (singleton == null),于是两个线程都对这个进行实例化,这样就出问题啦。

所以他们又说应该使用synchronize关键字,在实例化之前,进行加锁行为。于是又产生了一下的代码

public class Singleton {
    public static final Singleton singleton = null;
    private Singleton(){}
    public static Singleton getInstance(){
        if(singleton == null){ //如果singleton为空,表明未实例化
           synchronize (Singleton.class){
               if( singleton == null ) { // double check 进来判断后再实例化。
                   singleton = new Singleton(); 
               } 
        }
        return singleton;
    }
}

他们就会说,他们的这个代码使用了double check (双重检测),以防止这样的情况:当两个线程执行完第一个singleton == null 后等待锁, 其中一个线程获得锁并进入synchronize后,实例化了,然后退出释放锁,另外一个线程获得锁,进入又想实例化,会判断是否进行实例化了,如果存在,就不进行实例化了。

他们会说,这样的代码perfect,很完美,既解决了多线程带来的问题,又解决了延迟实例化的方式。

我觉得这样的代码只是将C++版的单例模式复制到Java平台,没有Java的特色。第一个就是一个Java特色的代码,它解决了多线程的问题,因为JLS(Java Language Specification)中规定了一个类(Singleton.class)只会被初始化一次,但是不能解决延迟实例化的情况。如需要延迟实例化,可以看下面的方法,使用内部类来实现。

使用内部类的单例模式 (懒汉模式)

刚才说了,第一个不能解决延迟实例化Singleton对象的问题。所以我们使用内部类来进行,看看代码。

//一个延迟实例化的内部类的单例模式
public final class Singleton {
    
    //一个内部类的容器,调用getInstance时,JVM加载这个类
    private static final class SingletonHolder {
        static final Singleton singleton =  new Singleton();
    }

    private Singleton() {}

    public static Singleton getInstance() {
        return SingletonHolder.singleton;
    }
 }

我们来看看这个代码。首先,其他类在引用这个Singleton的类时,只是新建了一个引用,并没有开辟一个的堆空间存放(对象所在的内存空间)。接着,当使用Singleton.getInstance()方法后,Java虚拟机(JVM)会加载SingletonHolder.class(JLS规定每个class对象只能被初始化一次),并实例化一个Singleton对象。

这样做就可以解决前面说的对线程多次实例化对象延迟实例化对象的问题了。

缺点:不过你会使用这样复杂的方式嘛?代码那么多。只是为了延迟一个对象的实例化,引入另外一个class。就为了延迟那么一次对象延迟的实例化,延缓Java的heap堆内存。为此付出的代价是引入一个class,需要在Java的另外一个内存空间(Java PermGen 永久代内存,这块内存是虚拟机加载class文件存放的位置)占用一个大块的空间。

还存在的一些问题

好了,在许多情况其实用第一种方法就差不多可以了。在特殊情况下,还是存在着一些问题。

用反射生成对象

如果使用Java的反射机制来生成对象的话,那么单例模式就会被破坏。

//使用反射破坏单例模式
Class c = Class.forName(Singleton.class.getName());  
Constructor constructor = c.getDeclaredConstructor();  
constructor.setAccessible(true);  
Singleton singleton = (Singleton)ct.newInstance();  

对于用反射破坏单例模式的,是不对其进行代码保护的,即由此造成的后果,由写反射的构建单例实例的人负责。所以我们就不用担心反射带来的问题了。

分布式上,解决单例模式

对于分布式上的单例模式,应该使用RMI(Remote Method Invocation 远程方法调用)来进行。或者使用web serivce,在单个服务器上存在单例,其他的机器使用SOAP协议进行访问。

不同的ClassLoader(类加载器)加载Singleton

在不同的ClassLoader加载Singleton,他们是不一样的。就像在不同的package中相同的类名,他们是不同的类。同样的,在不同的ClassLoader上加载的类,他们尽管代码一样,还是属于不同的类。

这样,需要自己写classloader,保证Singleton.class的加载唯一。

参考文章:http://www.oschina.net/question/9709_102019

单例模式的对象是否会被JVM回收?

对于这个问题,在还没实例化单例的时候,对象不存在,单实例化后,那么singleton的引用就存在的,只要Singleton.class存在虚拟机中。那么什么时候Singleton.class会被回收呢?对于这个问题,牵扯了许多的问题。因为Singleton对象存在,所以Singleton.class就也存在,这样形成了相互依赖,所以不会被JVM垃圾回收。

网上有个文章验证了他的想法 http://blog.csdn.net/zhengzhb/article/details/7331354

使用反序列化生成对象

如果你的Singleton序列化了,那么通过反序列化方式可以生成一个对象。通过增加readResolve方法来解决。如下

//最简单的封装单例改进版。饿汉模式。序列化及反序列化解决
public class Singleton implements java.io.Serializable {
    public static final Singleton singleton = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){ return singleton; }
    private Object readResolve() {  return singleton;   }  
}

使用clone()克隆对象

Object的clone()方法默认是抛出CloneNotSupportedException异常的,所以只要不覆盖该方法,调用的时候,也会抛出异常。

effective java作者提到用enum枚举来实现单例模式。

扩展阅读:使用enum来进行Java的单例模式:http://coolxing.iteye.com/blog/1446648

分类: Java

hibernate实体自关联映射

近日在开发系统的一个功能的时候出现问题了,花了6天寻找解决方案。先来看看数据库的category表

数据库category结构
类型
id int(11)
name varchar(255)
parent int(11)

遇见的问题

问题表述:当我从数据库中根据id取出一个category出来的时候,对名字进行更改,然后再保存,就会在数据库中insert一条父记录。此困惑确实不解。还有就是使用junit使用模拟http请求测试也不会出问题使用tomcat就又insert了。

Hibernate对象的3中状态

对于出现的问题有,说保存了一个瞬时对象,不能保存。hibernate object references an unsaved transient instance。关于瞬时态(transien)、游离态(detached、托管态)、持久态(persistent)这里有张图

Hibernate对象的3种状态,瞬时态(transien)、游离态(detached)、持久态(persistent)。通过hibernate的save、update等方法进行转换。 图片来源:http://blog.csdn.net/xiaokaibupabupa/article/details/6785208

有说法是从数据库中取出一个对象,状态变成持久态,在session关闭后,就变成游离态。要想关联的parent目录也想要持久态,需要在hibernate的映射文件中需要使用cascade=”all”或者cascade=”save-update”能使父目录变为持久态。但是我在设添加此设置不管用,还是会想数据库insert一条记录。

我让许多同学来查看代码,都觉得没有什么问题,我就让我同学在自己的电脑上假设一个环境来测试,在他的电脑上也没问题。将同学的配置文件弄到自己的机器上测试,过了许多天,这个问题都没解决。

于是我就从MyEclipse的自带的Hibernate Inverse Engineering功能从数据库导出DAO文件、pojo文件、映射文件。然后将我自己的映射文件按照自动生成的来替换。但是还是不行。

更为烦恼的是,自己使用junit写的测试用例,来模拟http请求,能正确执行,但是通过tomcat来运行就又会出现insert的情况。

不过我在查看控制台的输出的时候,发现取出category进行了一个事务和session,update的时候又进行了一个事务和session。我觉得有点问题,因为这样使用了两个事务,我觉得在Spring的配置事务出现了一些问题。

现在把处理category逻辑放到了service层来进行,本来是在action层,感觉情况有些好转。

hibernate映射文件

把配置文件给贴出来看看,hibernate对象自关联自身配置。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.chenyudong.pojo.Category" >
        <id name="id" column="id" >
            <generator class="identity" ></generator>
        </id>
        <property name="name" column="name" />
        <set name="childCategory" inverse="true" cascade="all"  fetch="join" lazy="false">
            <key column="parentID"></key>
            <one-to-many class="com.chenyudong.pojo.Category" />
        </set>
        <many-to-one name="parent" class="com.chenyudong.pojo.Category"
            column="parentID" ></many-to-one>
    </class>  
</hibernate-mapping>

我们可以看见,在外键的一方,需要使用many-to-one或者其他的one-to-one或者one-to-manymany-to-many配置映射关系。此hibernate的映射关系,相当于数据库中的外键关联。many-to-one说明可以多个目录的parentID相同,指向同一个父目录。而set这个标签,则用于主键一方上,表明指向该记录的集合。

属性inverse描述的是对象之间关联关系的控制方向,也就是由哪个对象来维护他们之间的关联,而属性casade描述的是层级之间的连锁操作方式,也就是一个对象的改变是否也要同步对其管理对象进行相应的操作。

嗯,在耽误了许久的项目后继续赶进度了。

分类: JavaEE

解决Could not create the Java Virtual Machine

安装完openjdk64bit之后,运行java出现问题。

本篇记录tomcat的配置。请新建文件${TOMCAT}/bin/setenv.sh(或者Windows下:${TOMCAT}/bin/setenv.bat),tomcat会自动读取该配置。

OutOfMemoryError: Java heap space 堆空间不足

Error occurred during initialization of VM Could not reserve enough space for object heap Error: Could not create the Java Virtual Machine.

发现是虚拟机要使用的堆容量不足。

修改环境变量,调整堆内存大小

1.Linux修改环境变量

vi /etc/environment

2.增加此行

export _JAVA_OPTIONS="-Xms64m -Xmx64m -Xmn32m"

其中的64m表示使用64M的内存。-Xms是堆的最小大小,-Xmx是堆的最大值,-Xmn是堆中的新生代最小值。Xmn中的值不能超过总的堆内存大小

3.生效环境变量

source /etc/environment

4.运行java。看看能否运行,如果还是不能运行,到第二步,减小内存。

java -version

OutOfMemoryError: PermGen space 永久代保存区域溢出

PermGen是虚拟机中的永久代,不属于堆。里面主要有class的信息等。出现这个错误一般都是加载的class过多了。比如你的tomcat有许多的应用,每个应用的class文件或者jar包非常多。虽然Java在运行程序时,根据需要加载class文件,但是一旦加载后,移除该class的就会比较少了,但是java肯定有这个机制,只是这个机制的判断比较复杂,要如何判断一个class不再使用,确实比较麻烦。

要设置Java的PermGen,见下面的参数

JAVA_OPTIONS="-XX:PermSize=64M -XX:MaxPermSize=128m"

这个是设置初始的PermGen的大小为64M,最大的PermGen为128m。

分类: Java

struts action json 示例

想使用Ajax来请求数据,但是后台都是使用struts和一堆的Action写的,这个要如何写呢?

大家应该都知道JSON和Ajax是什么吧?如果还不知道也不会继续阅读下去。

采用Action来返回JSON数据

第一步,导入struts2-json-plugin.jar包。如果没有该jar包,那么到http://struts.apache.org/download.cgi下载一个struts包,里面包含该jar包。

第二步:编写一个Action类

package com.chenyudong.action;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import com.opensymphony.xwork2.ActionSupport;

public class AjaxAction extends ActionSupport {
    private static final long serialVersionUID = -5279892367628798557L;
    
    Map<String,Object> map = new HashMap<String,Object>();
    List<Object> list = new LinkedList<Object>();

    public Map<String, Object> getMap() {return map;}
    public void setMap(Map<String, Object> map) {this.map = map;}
    public List<Object> getList() {return list;}
    public void setList(List<Object> list) {this.list = list;}

    public String test(){
        map.put("username", "abc"); 
        return SUCCESS;
    }
}

第三步:配置struts.xml文件

<package name="struts2" extends="struts-default,json-default">
    <action name="ajax" class="com.chenyudong.action.AjaxAction" method="test">
        <result type="json"></result>
    </action>
</package>

第四步:访问网页得到结果

{"list":[],"map":{"username":"abc"}}

该方法需要注意的地方,在AjaxAction类中,有成员变量map和list,在方法中,我没有使用list成员变量,由于设置get和set方法,我的输出结果中,有list值。也就是使用该方法,会出现成员变量中的所有有get的成员都会输出。如果想要不想显示无关的list或者map,使用注解@JSON(serialize=false)

分类: JavaEE

java 64bit 32bit environment path install

在编写Java程序的时候,程序员需要安装JDK,JDK里面已经包含了JRE,JRE里包含了JVM虚拟机了。Eclipse的运行需要JRE的支持。所以我们需要JRE。 JDK有64bit和32bit之分,Eclipse也有64bit和32bit之分。

为什么是64bit?

现在内存越来越大,而32bit的系统只能寻址4G的空间,由于一些系统中断的地址占用,32bit的系统只能识别3G的内存。要想充分利用剩余的内存,只能换成64bit操作系统。

64bit有什么劣势

由于64bit的系统是最近发展起来的,有的软件只能运行于32bit上,在64bit环境中不是太好,所以软件的兼容性是需要解决的。许多人不愿升级到64bit操作系统就是这个原因。

为什么需要32bit的JDK

写一个项目需要使用JMF,而JMF是2002年左右出来的东西,当时还不支持64bit的系统。于是在我的64bit的JDK上不能运行,会报错误。无奈,只能从别人的32bit的JDK拷贝到我的电脑上运行。

更改环境之前需要做什么

删除一些文件。如果系统之前是使用exe安装方式安装的JDK,那么在C://windows/system32会有3个文件,是java.exe javaw.exe javaws.exe。为什么当时使用exe安装JDK的时候不要配置环境变量,就可以运行java程序?就是因为安装文件在这个目录下放了这几个文件。

获得32bit的JDK。可以下载一个32bit的JDK。

获得32bit的Eclipse。如果直接在32bit的jre上运行64bit的eclipse会出现问题的。会出现如下错误

Failed to load the JNI shared library "F:\jdk1.7.0_03\bin\..\jre\bin\client\jvm.dll".

如何更改环境变量

右键计算机-属性,高级系统设置。

检测是否成功

打开cmd,输入命令java -version

分类: Java

MyEclipse禁用JavaScript检查功能

Myeclipse对Javascript的检测特别不习惯,有时候JS文件里面加着struts代码,就会报错。只能禁用JavaScript检查功能了。

在MyEclipse的Project目录下有一个隐藏文件.project,这个文件放着一些project的配置

我直接贴出来吧,将以下的删除即可。

<buildcommand>
    <name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
    <arguments>
    </arguments>
</buildcommand>

<nature>org.eclipse.wst.jsdt.core.jsNature</nature>

具体情况可见该文件。这样重启MyEclipse就不会启用Javascript检查功能了。

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
    <name>trybest</name>
    <comment></comment>
    <projects>
    </projects>
    <buildSpec>
        <buildCommand>
            <name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
            <arguments>
            </arguments>
        </buildCommand>
        <buildCommand>
            <name>org.eclipse.wst.common.project.facet.core.builder</name>
            <arguments>
            </arguments>
        </buildCommand>
        <buildCommand>
            <name>com.genuitec.eclipse.j2eedt.core.WebClasspathBuilder</name>
            <arguments>
            </arguments>
        </buildCommand>
        <buildCommand>
            <name>org.eclipse.jdt.core.javabuilder</name>
            <arguments>
            </arguments>
        </buildCommand>
        <buildCommand>
            <name>com.genuitec.eclipse.j2eedt.core.J2EEProjectValidator</name>
            <arguments>
            </arguments>
        </buildCommand>
        <buildCommand>
            <name>com.genuitec.eclipse.j2eedt.core.DeploymentDescriptorValidator</name>
            <arguments>
            </arguments>
        </buildCommand>
        <buildCommand>
            <name>org.eclipse.wst.validation.validationbuilder</name>
            <arguments>
            </arguments>
        </buildCommand>
        <buildCommand>
            <name>com.genuitec.eclipse.ast.deploy.core.DeploymentBuilder</name>
            <arguments>
            </arguments>
            </buildCommand>
    </buildSpec>
    <natures>
        <nature>com.genuitec.eclipse.ast.deploy.core.deploymentnature</nature>
        <nature>com.genuitec.eclipse.j2eedt.core.webnature</nature>
        <nature>org.eclipse.jdt.core.javanature</nature>
        <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
        <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
        <nature>org.eclipse.wst.jsdt.core.jsNature</nature>
    </natures>
</projectDescription>

分类: JavaEE

log4j.properties配置文件使用说明

log4j是一个用于Java的控制信息的输出类库,下载地址apache log4j

log4j.properities是log4j的配置文件,放在classpath的根目录下。在运行时,log4j会自动查找配置文件log4j.properities,读取配置。

log4j可以用来代替System.out.println();来控制输出,有一天,可能想让输出到一个文件中去,或者不显示。毕竟不是所有的运行情况都能在控制台上运行并输出。

根记录等级

log4j.rootLogger = debug,CONSOLE,FILE;

说明我的所有的Log将来输出的最低级别是debug,并且使用CONSOLE和FILE输出目的地。其中CONSOLE、FILE只是一个命名变量,在下方具体指定不同的配置。

日志记录器Logger有5个正常级别level,分别是 debug 调试程序时输出的信息 info 应用程序在运行过程的信息 warn 会出现潜在错误信息 error 指出虽然会发生错误,但还不会影响程序继续运行 fatal 指出致命错误,会会导致应用程序退出

另外还有两个特别的日志记录级别 all 最低等级,用于显示所有日志记录 off 最高等级,用于关闭所有日志记录

显示内容的多少,是all>debug>info

输出源Appender log4j提供5个appender输出源,它们是 org.apache.log4j.ConsoleAppender

分类: Java

hibernate mysql 中文乱码异常

用Hibernate往mysql 5.1数据库中进行查询数据,表的结构使用的是utf-8编码,服务器在Linux上,这个时候往数据库上查询,插入没问题。后来往5.1的数据库导入模型的时候,外键不见了,于是在Windows本地安装了一个mysql 5.5的数据库,导入模型正常。但是进行查询的时候抛出异常说

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?? as ??0_, owner0_.??? as ???0_, owner0_.?? as ??0_, owner0_.???? as ????0_ fro' at line 1

但是上面的Hibernate自动生成的sql语句显示不会乱码,当然,这两者没关系,表示我的这个sql语句是没有问题的。

于是我在Windows的mysql5.1中建立一个同样的数据库,发现也是这样的错误。

尝试尝试是否是编码的问题,我检查数据库都是用UTF-8编码设置的,没发现有什么异常。

最后在hibernate.cfg.xml上的session-factory中添加编码设置,最后的文件配置是这样的。

<session-factory>

    <property name="connection.url">jdbc:mysql://localhost:3306/test</property>
    <property name="connection.username">root</property>
    <property name="connection.password">password</property>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="connection.useUnicode">true</property>
    <property name="connection.characterEncoding">UTF-8</property>

    <property name="show_sql">true</property>

    <mapping resource="owner.hbm.xml" />

</session-factory>

分类: JavaEE

较早的文章

Copyright © 2017 东东东 陈煜东的博客 粤ICP备13059639号-1

SITEMAP回到顶部 ↑