EJB3.0 JPA 增删改查 模拟用户登录、注册用户、事物处理(详细)

貌似最近EJB3.0很流行\自己也开始学了下,其实如果对spring、hibernate比较熟悉的话ejb3.0其实很简单

ejb3.0也有依赖注入、AOP事务管理及hibernate的延迟加载这些东西和spring、hibernate大致做法是一致的!

 

学习ejb3.0之前必须先理解如下:

1、什么是会话bean、什么是实体bean(bean不知道中文对应的字,写成豆有点别扭 ,呵呵文盲sessionBean、entityBean)

//插一句什么是消息驱动bean 其实这个实例中没有介绍,所以我也不说明了~

2、有状态bean和无状态bean的区别

开发环境及工具:

 

1、jdk1.5

2、jboss-4.2.3.GA(必须4.2.xx版本才支持ejb3.0啊)

3、MyEclipse 5.5.1 GA

4、mysql

 

我使用MyEclipse 5.5.1 GA 主要是工作中习惯了它,其它高版本还不太适应,高版本建立ejb3.0应该一样89不离10哈

如果只有EclipseJ2EE 版本的话就需要将jboos中的D:\jboss-4.2.3.GA\server\default\lib的jar文件加入到根目录,这个不做介绍了哈,本机没有jee版本

 

EJB都是通过容器来连接数据库的,程序通过JNDI来调用

在建立项目之前先进入jboss 目录:D:\jboss-4.2.3.GA\docs\examples\jca 找到mysql-ds.xml ,因为我使用的是mysql所以就要它另存为其它地方,如果是oracle或db2找相对应的就OK

然后修改下数据库连接及其它设置修改如下

<?xml version="1.0" 

encoding="UTF-8"?>


<datasources>
  <local-tx-datasource>
    <jndi-name>demoDS</jndi-name>
    <connection-

url>jdbc:mysql://127.0.0.1:3306/demo</connection-url>
    <driver-class>com.mysql.jdbc.Driver</driver-class>
    <user-name>root</user-name>
    <password>root</password>
    <min-pool-size>3</min-pool-size>
    <max-pool-size>10</max-pool-size>
    <exception-sorter-class-

name>org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter<

/exception-sorter-class-name>
    <metadata>
       <type-mapping>mySQL</type-mapping>
    </metadata>
  </local-tx-datasource>
</datasources>


以上数据库设置就好了,不需要写代码哦···简单的爽·················然后把修改后的配置文件复制到jboss目录:D:\jboss-4.2.3.GA\server\default\deploy下

启动jboss数据库连接就O了·

 

请记住<jndi-name>demoDS</jndi-name> 后面项目建立的时候需要用到

现在开始建立EJB3.0项目

 

 

内容如下:

<?xml version="1.0" 

encoding="UTF-8"?>
<persistence 

xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" 

version="1.0">
    
	<persistence-unit name="demo" transaction-

type="JTA">
  		<jta-data-source>java:demoDS</jta-data-

source>
	</persistence-unit>
  
</persistence>

transaction-type="JTA" 一定要是JTA事物啊,这个可是支持分布式事物的啊!

项目各种包的一个展示,对应有过开发项目的人来说应该是明白的我还是具体说明下

org.demo.jpa.dao  dao层的接口

org.demo.jpa.dao.impl dao层的实现类

org.demo.model  这里指实体bean说简单点就是对应数据库的java bean对象(这样说有一点不对,它不是简单java bean,它属于ejb的bean)

org.demo.service 服务层的接口

org.demo.service.impl 服务层实现类

 

META-INF这个是JTA规范

 


首先数据库建立两张表,user表和book表,本打算介绍下懒加载的,但因为时间问题,这个以后在说了,暂时不介绍了,所以实际只用到了user表

我是反向工程,先建立表结构然后通过工具生成数据库javaBean模型

数据库代码:

 

-- Table "user" DDL

CREATE TABLE `user` (
  `id` int(11) NOT NULL auto_increment,
  `userName` varchar(10) NOT NULL,
  `passWord` varchar(10) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `userName` (`userName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


-- Table "book" DDL

CREATE TABLE `book` (
  `id` int(11) NOT NULL auto_increment,
  `bookName` varchar(255) NOT NULL,
  `user` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `user` (`user`),
  CONSTRAINT `book_ibfk_1` FOREIGN KEY (`user`) R


数据库表建立好后,现在通过MyEclipse来自动生成代码

 

右上角--字打错了,改 :如果没有上面红线部分点击other可以找到

 

 

 

反转好后model包下就有如下两个java代码,由于用了工具生成,但工具未帮我们设置主键增长方式

需要我们手动添加代码,点击User.java、Book.java 找到 public Integer getId()方法添加如下代码

@GeneratedValue(strategy=GenerationType.AUTO) 这个是设置默认状态

代码如下

User.java

package org.demo.model;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
 * User generated by MyEclipse Persistence Tools
 */
@Entity
@Table(name = "user", catalog = "demo", uniqueConstraints = {})
public class User implements java.io.Serializable {


	/**
	 * 
	 */
	private static final long serialVersionUID = 5080524625071021061L;

	private Integer id;

	private String userName;

	private String passWord;

	private Set<Book> books = new HashSet<Book>(0);

	// Constructors

	/** default constructor */
	public User() {
	}

	/** minimal constructor */
	public User(Integer id, String userName, String passWord) {
		this.id = id;
		this.userName = userName;
		this.passWord = passWord;
	}

	/** full constructor */
	public User(Integer id, String userName, String passWord, Set<Book> books) {
		this.id = id;
		this.userName = userName;
		this.passWord = passWord;
		this.books = books;
	}

	// Property accessors
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true)
	public Integer getId() {
		return this.id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@Column(name = "userName", unique = true, nullable = false, insertable = true, updatable = true, length = 10)
	public String getUserName() {
		return this.userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	@Column(name = "passWord", unique = false, nullable = false, insertable = true, updatable = true, length = 10)
	public String getPassWord() {
		return this.passWord;
	}

	public void setPassWord(String passWord) {
		this.passWord = passWord;
	}

	@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, mappedBy = "user")
	public Set<Book> getBooks() {
		return this.books;
	}

	public void setBooks(Set<Book> books) {
		this.books = books;
	}

}


book.java

package org.demo.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 * Book generated by MyEclipse Persistence Tools
 */
@Entity
@Table(name = "book", catalog = "demo", uniqueConstraints = {})
public class Book implements java.io.Serializable {

	// Fields

	/**
	 * 
	 */
	private static final long serialVersionUID = 5006758001351352346L;

	private Integer id;

	private User user;

	private String bookName;

	// Constructors

	/** default constructor */
	public Book() {
	}

	/** full constructor */
	public Book(Integer id, User user, String bookName) {
		this.id = id;
		this.user = user;
		this.bookName = bookName;
	}

	// Property accessors
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = true)
	public Integer getId() {
		return this.id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	@ManyToOne(cascade = {}, fetch = FetchType.LAZY)
	@JoinColumn(name = "user", unique = false, nullable = false, insertable = true, updatable = true)
	public User getUser() {
		return this.user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@Column(name = "bookName", unique = false, nullable = false, insertable = true, updatable = true)
	public String getBookName() {
		return this.bookName;
	}

	public void setBookName(String bookName) {
		this.bookName = bookName;
	}

}


现在模型生成好了,现在写dao层代码

首先我是把dao层抽象出来,不是每一service对应一个dao,而是所有的service调用一个dao

这个也是我们公司一直这样做的,JpaDao.java这个接口,我只实现了查询和保持接口,写的比较简单,够这个demo就OK了

 

JpaDao.java 接口

package org.demo.jpa.dao;

import java.util.List;
import java.util.Map;

public interface JpaDao {
	/**
	 * 查询接口
	 * @param jpaql jpaql语句
	 * @param parameters 数组参数
	 * @return 返回对象数组
	 */
	public List<Object> find(String jpaql, Object[] parameters);
	/**
	 * 查询接口
	 * @param jpaql jpaql语句
	 * @param parameters Map作为参数key指占位符字符串,value指具体的值对象
	 * @return 返回对象数组
	 */
	public List<Object> find(String jpaql, Map<String, Object> parameters);
	
	/**
	 * 保存持久化对象
	 * @param obj 持久化对象
	 */
	public void save(Object obj);
	
	
}


JpaDaoImpl.java 实现类

package org.demo.jpa.dao.impl;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.demo.jpa.dao.JpaDao;
/**
 * 这就不做过多的介绍了哈,不明白请查看UserServiceImpl中的注释说明
 * 
 * jpa是什么我大概说下我的理解哈,他就是J2EE官方规范,对orm框架做的一个统一接口
 * 就有点类似于jdbc规范,sun只给一个jdbc接口,具体如何实现由oracle\mysql\db2\....来实现
 * 还是那句话可能说的不完全正确,但说到点子上就OK
 * 如果学过hibernate 对jpa学起来就快了,HQL和JPAQL 也非常类似
 * @author Administrator
 *
 */
@Stateless
@Local //申明一个本地的会话并\兵\饼(sessionBean不知道中文应该怎么打bean)
public class JpaDaoImpl implements JpaDao {
	
	//申明一个持久化上下文\这个就是jta(JTA 事务定义管理)规范 unitName="demo"
	// demo 这个字符串是 /META-INF/persistence.xml文件中的
	// <persistence-unit name="demo" transaction-type="JTA"> 的name字段
	// EntityManager em; 实体管理器,这里就有点像hibernate中的sessionFactory了哈,个人理解的哈
	// 不一定正确
	
	@PersistenceContext(unitName="demo") EntityManager em;
	
	
	
	//@SuppressWarnings("unchecked") 这个不是ejb的注释,这是一个去除警告的注释
	@SuppressWarnings("unchecked")
	public List<Object> find(String jpaql, Object[] parameters) {
		//查询接口
		Query query = em.createQuery(jpaql);
		
		for (int i = 0; i < parameters.length; i++) {
			
			Object parameter = parameters[i];
			
			query.setParameter(i+1, parameter);
		}
		
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<Object> find(String jpaql, Map<String, Object> parameters) {
		Query query = em.createQuery(jpaql);

		Iterator<Entry<String, Object>> it = parameters.entrySet().iterator();

		while (it.hasNext()) {

			Map.Entry<String, Object> entry = it.next();

			query.setParameter(entry.getKey(), entry.getValue());
		}

		return query.getResultList();
	}

	public void save(Object obj) {
		//类似hibernate.save(Object ojb);
		em.persist(obj);
		
	}
}


做到现在Dao层就完成了

现在开始实现service层

UserService.java   接口

package org.demo.service;
import java.util.List;

import org.demo.model.User;


public interface UserService {
	
	public User verifyUser(String username,String password);
	
	public void saveUser(User user);
	
	public void saveUser(List<User> users);
	
}


UserServiceImpl.java 实现类 

注释写的很清楚了哈,·

package org.demo.service.impl;

import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;

import org.demo.jpa.dao.JpaDao;
import org.demo.model.User;
import org.demo.service.UserService;
/*这是一个可远程访问的Session Bean */
@Stateless // @Stateless 声明这是一个无状态sessionBean
@Remote    // @Remote 声明这是一个可远程调用的sessionBean,如果未声明默认为local(本地),本地可以节省网络开销,需在同一个jvm中,内存调用

//声明事物 事物分为两种(CMP、BMP)cmp可以理解为api事物(也可理解为用程序来控制事物),bmp可以理解为容器来处理事物(无需要写代码)
//@TransactionManagement(TransactionManagementType.CONTAINER) 我们用的是bmp事物,我完全是用白话文说的哈,可能说的不对,见谅
//我书读的不多,也许说得不够准确,但大概意思是说到了的,如果不明白建议google、baidu
@TransactionManagement(TransactionManagementType.CONTAINER)


public class UserServiceImpl implements UserService {
	//@EJB 这里指调用同一个jvm的ejb对象
	@EJB JpaDao jpaDao;
	
	/*验证用户信息*/
	public User verifyUser(String username, String password) {
		List<Object> users =jpaDao.find("from User u where u.userName=?1 and u.passWord=?2", new Object[]{username,password});
		return (User) (users.isEmpty()?null:users.get(0));
	}
	
	//保持用户信息
	//常用的事物类型2种
	// 1、REQUIRED 大概意思是,如果事物不存在创建一个,如果事物存在就调用当前事物,还是那句话不明白就google
	// 2、REQUIRES_NEW 大概意思,无论事物是否存在都,再次创建一个事物
	@TransactionAttribute(TransactionAttributeType.REQUIRED)//这里声明一个事物类型
	public void saveUser(User user) {
		jpaDao.save(user);
	}
	
	//	做一个类似批量保存,本应该抽象在dao层来做批量,但为了事物所以写在这个方法中~ 加入事物后保持一致性,如果有一条不成功,回滚
	//  这个就有点像spring的aop面向切面编程,意思就是这个方法开始之前执行一个行为,结束之前在执行一个行为,事物也就可以用在这里了
	//  调用public void saveUser(List<User> users)这个方法之前打开一个事物,当这个方法执行完之前提交事物,并关闭当前会话session
	//  自我感觉说的很明白了哈,如果还是无法理解请google..呵呵
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void saveUser(List<User> users) {
		
		for(User user : users){
			jpaDao.save(user);
		}
		
	}

}


好了现在model、dao、service 都做好了,那么就代表EJB服务端已经完成

现在开始做客户端远程调用的例子了,我把客户端,写到另外一个项目里,这个项目是一个普通的java项目

当然web项目也可以实现,原理是一样的~,web项目写着麻烦,在jsp里写,我是不太习惯,在servlet里写比较好,但麻烦所以,就用一个main函数搞定

 

建立一个普通的java项目,这个任何一个人都会,我就不啰嗦了~

项目名称叫:Test

项目结构如下

项目搭建好后,引入EJB项目,如下图

 

点OK后EJB项目引用就完成了~

现在还没完需要进入jboss目录:D:\jboss-4.2.3.GA\client  找到一个名为:jbossall-client.jar 复制一下,第二排第六个,呵呵我的是,不知道你的是不是???

粘贴到刚才建立的Test 项目根目录

我的是没有src的,有src的请放到src下面,然后如图

弄好后,就会出现一个瓶子状的东西,就代表jar文件引用成功

再然后 进入jboss目录:D:\jboss-4.2.3.GA\server\default\conf 找到一个叫jndi.properties的文件复制到根目录

 

修改成如下: 这东西不想过多的说明,jboos统一的上下文哈,不需要去背,

java.naming.provider.url=localhost:1099 这个就是调用ejb的地址和端口号,这个端口号可以去jboss目录:D:\jboss-4.2.3.GA\server\default\conf

jboss-service.xml中去修改或查找

# DO NOT EDIT THIS FILE UNLESS YOU KNOW WHAT YOU ARE DOING
#
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost:1099


 

现在编写Test.java类

package com.test;

import java.util.ArrayList;
import java.util.List;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.demo.model.User;
import org.demo.service.UserService;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		try {
			//初始化上下文   jndi.properties
			InitialContext ic = new InitialContext();
			
			//ic.lookup("UserServiceImpl/remote");这个就是调用EJB会话饼(sessionBean)
			//remote就是调用远程的哈,我用的是一个main函数所以不在同一个jvm里面,必须使用远程调用
			//local是本地调用,如果你用xx.jsp而且在ejb同一个项目中那么就可以本地调用了
			UserService userSercice = (UserService) ic.lookup("UserServiceImpl/remote");
			//用户查询(模拟登录) 现在数据库没有数据所以 返回 "无此用户"
			User user = userSercice.verifyUser("xiaomaha", "qq123"); //查询操作
			System.out.println(null==user?"无此用户":user.getUserName());
			
			System.out.println("1:-----------------------分割线-----------------------");
			
			//添加一个用户(模拟注册,验证免了哈)
			User user2 = new User();
			user2.setUserName("xiaomaha");
			user2.setPassWord("qq123");
			userSercice.saveUser(user2); //保存操作
			System.out.println("保存完成!!");
			
			System.out.println("2:-----------------------分割线-----------------------");
			
			//批量添加用户(这个主要用来测试事物\如果有一条失败就回滚)
			//userName数据库设置成唯一约束,所以执行后xiaomaha2\xiaomaha都不应该存在于数据库中(回滚)
			List<User> users = new ArrayList<User>();
			//第一个user对象			
			User user3 = new User();
			user3.setUserName("xiaomaha2");
			user3.setPassWord("qq123");
			//第二个user对象	
			User user4 = new User();
			user4.setUserName("xiaomaha"); //前面已经保存了xiaomaha,这里在保存就会有异常
			user4.setPassWord("qq123111");
			//保存到list中
			users.add(user3);
			users.add(user4);
			//调用ejb sessionBean接口
			userSercice.saveUser(users);
			
			System.out.println("3:-----------------------分割线-----------------------");
			
			//用户查询(模拟登录) 现在数据库已经有了 返回 当前用户的名称
			User user5 = userSercice.verifyUser("xiaomaha", "qq123"); //查询操作
			System.out.println(null==user5?"无此用户":user5.getUserName());
			
			//最后的数据库里面如果只有xiaomaha这个用户那么就代表程序完成
			
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}


最后执行会有异常因为事务回滚了,我是故意这样做的~为了演示事物·····

数据库数据··

不想看到事物回滚,请让userName的值不要重复就不会有异常了,这个大家都知道,貌似我说了也是白说,贴下无异常代码

package com.test;

import java.util.ArrayList;
import java.util.List;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.demo.model.User;
import org.demo.service.UserService;

public class Test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		try {
			//初始化上下文   jndi.properties
			InitialContext ic = new InitialContext();
			
			//ic.lookup("UserServiceImpl/remote");这个就是调用EJB会话饼(sessionBean)
			//remote就是调用远程的哈,我用的是一个main函数所以不在同一个jvm里面,必须使用远程调用
			//local是本地调用,如果你用xx.jsp而且在ejb同一个项目中那么就可以本地调用了
			UserService userSercice = (UserService) ic.lookup("UserServiceImpl/remote");
			//用户查询(模拟登录) 现在数据库没有数据所以 返回 "无此用户"
			User user = userSercice.verifyUser("xiaomaha", "qq123"); //查询操作
			System.out.println(null==user?"无此用户":user.getUserName());
			
			System.out.println("1:-----------------------分割线-----------------------");
			
			//添加一个用户(模拟注册,验证免了哈)
			User user2 = new User();
			user2.setUserName("xiaomaha10");
			user2.setPassWord("qq123");
			userSercice.saveUser(user2); //保存操作
			System.out.println("保存完成!!");
			
			System.out.println("2:-----------------------分割线-----------------------");
			
			//批量添加用户(这个主要用来测试事物\如果有一条失败就回滚)
			//userName数据库设置成唯一约束,所以执行后xiaomaha2\xiaomaha都不应该存在于数据库中(回滚)
			List<User> users = new ArrayList<User>();
			//第一个user对象			
			User user3 = new User();
			user3.setUserName("xiaomaha11");
			user3.setPassWord("qq123");
			//第二个user对象	
			User user4 = new User();
			user4.setUserName("xiaomaha12"); //前面已经保存了xiaomaha,这里在保存就会有异常
			user4.setPassWord("qq123111");
			//保存到list中
			users.add(user3);
			users.add(user4);
			//调用ejb sessionBean接口
			userSercice.saveUser(users);
			
			System.out.println("3:-----------------------分割线-----------------------");
			
			//用户查询(模拟登录) 现在数据库已经有了 返回 当前用户的名称
			User user5 = userSercice.verifyUser("xiaomaha12", "qq123111"); //查询操作
			System.out.println(null==user5?"无此用户":user5.getUserName());
			
			//最后的数据库里面如果只有xiaomaha这个用户那么就代表程序完成
			
		} catch (NamingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

}


打印结果:

 

over````````````````bye`

 

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值