1:OSIV模式 - Open Session In View
2:让项目中的所有代码成为单例。
1:在项目中一个Service调用多个Dao的情况下
解决方案1:
将所有代码:
1:传递同一个Connection给每一个Dao。
2:在Serice里面控制事务。即try..catch..fnally。
上面的问题:
1:让Connection这个连接对象暴露在了Service层。
2:在项目中,有N个Service,在每一个Service中都写try..catch..finally代码量太大,重复太多。
3:给每一个dao需要多传递一个参数。即Connection参数。
解决方案2:
在Java中有一个类ThreadLocal - 维护线程局部的变量。
此类看上去像是线程,但是本质是容器即是一个HashMap。它的结构是:Map<Thead,Object>即,以线程为key,以任意的对象为value保存值。
1:思想
修改DSUtils类,维护一个唯一的线程局部的对象。
// 声明ThreadLocal
private static ThreadLocal<Connection> tl;
static {
tl = new ThreadLocal<>();
dataSource = new ComboPooledDataSource();
}
public static DataSource getDataSource() {
return dataSource;
}
public static Connection getConnection() {
Connection con = tl.get();// 先从tl获取连接,查看当前线程是否保存过连接
if (con == null) {
try {
con = dataSource.getConnection();
// 放到tl
tl.set(con);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return con;
}
2:添加过虑器 /stud
package cn.filter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import cn.meeting.utils.DSUtils;
@WebFilter(urlPatterns = "/stud")
public class TxFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 1:获取
Connection con = DSUtils.getConnection();
try {
con.setAutoCommit(false);
chain.doFilter(request, response);
con.commit();
} catch (Exception e) {
try {
con.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
throw new RuntimeException(e);
} finally {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
DSUtils.remove();
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
OSIV模式,将事务的控制做为Filter层。
上面的问题是:
事务太靠前了。在过虑器层。
如果在调用servlet时,事务已经开始。但是在servlet中出错了,即还没有service/dao呢。
转发时,如果不是SQL异常也回滚。
可以通过catch只对sql异常进行rollback;
解决方案3:
可以使用代理代理所有Service。
package cn.utils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import cn.meeting.utils.DSUtils;
public class TxProxy {
public static Object newProxy(final Object src) {
Object proxyObj = Proxy.newProxyInstance(TxProxy.class.getClassLoader(), src.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Connection con = DSUtils.getConnection();
System.err.println("获取连接.." + con);
Object returnValue = null;
try {
System.err.println("开始事务");
con.setAutoCommit(false);
returnValue = method.invoke(src, args);// 放行
System.err.println("提交");
con.commit();
} catch (Exception e) {
System.err.println("出错了回滚");
con.rollback();
throw e;
} finally {
con.close();
DSUtils.remove();
}
return returnValue;
}
});
return proxyObj;
}
}
@WebServlet("/stud")
public class StudServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private IStudService service = (IStudService) TxProxy.newProxy(new StudServlet());
2:ThreadLocal
java.lang
类 ThreadLocal<T>
java.lang.Object
java.lang.ThreadLocal<T>
直接已知子类:
InheritableThreadLocal
public class ThreadLocal<T>
extends Object
该类提供了线程局部 (thread-local) 变量
变量:
三种: 1:局部,2:成员, 3:线程局部。
1:用ThreadLocal保存数据
@Test
public void test1() {
// 1:实例化容器Map<Thread,T>
ThreadLocal<Object> tl = new ThreadLocal<>();
tl.set("Jack");
// 获取里面的值
Object val = tl.get();
System.err.println(val);
}
// 1:实例化容器Map<Thread,T>
ThreadLocal<Object> tl = new ThreadLocal<>();//Map<Thread,T>
tl.set("Jack");//map.put(Thread.currentThread(),"Jack");
tl.set("Mary");//map.put(Thread.currentThread(),"Mary"); //后面覆盖前面的值
// 获取里面的值
Object val = tl.get();//Mary
System.err.println(val);
2:单例化ThreadLocal
保存当前某个线程的局部的变量-线程局部的变量。
在一个项目中,只要有一个TL对象,就可以为所有线程提供服务。
@Test
public void teest1() throws Exception{
Object obj1 = TLUtils.random();
System.err.println("1:"+obj1);
abc();
new Thread(){
public void run() {
Object obj1 = TLUtils.random();
System.err.println("3:"+obj1);
abc();
};
}.start();
System.in.read();
}
public void abc(){
Object obj1 = TLUtils.random();
System.err.println(Thread.currentThread().getName()+" 2:"+obj1);
}
}
3:自己开发ThreadLocal对象
思想:
自己开发一个集合Map<Thred,Object>
public class TLUtils2 {
private static Map<Thread, Object> tl;
static {
tl = new HashMap<Thread, Object>();
}
public static Object get() {
Object obj = tl.get(Thread.currentThread());
if (obj == null) {
obj = new Random().nextInt(100);
tl.put(Thread.currentThread(), obj);
}
return obj;
}
}
上面的类的问题:
1:做为HashMap,即集合类,只看到了不断的获取数据,和不断的保存数据
没有看到从map中删除数据。
则Map的中的值越来越多。最后总是会造成对象太多而崩溃。
2:所以,当某个对象不在被使用以后,应该及时清理掉。
在ThreadLocal中是如何清理的:
void | remove() |
3:所以,上面的自己开发的线程局部,也必须要提供一个方法,用于删除
public class TLUtils2 {
private static Map<Thread, Object> tl;
static {
tl = new HashMap<Thread, Object>();
}
public static Object get() {
Object obj = tl.get(Thread.currentThread());
if (obj == null) {
obj = new Random().nextInt(100);
tl.put(Thread.currentThread(), obj);
}
return obj;
}
public static void remove(){
tl.remove(Thread.currentThread());
}
}
上面的问题是:
用户必须要显式的调用remove才可以。
2.2、对象的引用
对象的引用为分为四种:
强引用
Person p = new Person();
此时p变量,new Person()叫对象,此时 new Peson这个对象被 p这个变量强引用。
在Java代码中, 如果内存不够了则 GC会回收内存。但是如果对象有强引用。但是内存又不够用了,JVM直接崩溃也不会回收强引用的内存。
弱
如果内存不够了,则会回收这个内存。
软
如果内存不够了,则会回收这个内存。放到回收队列。
虚
内存无论是否足够,则直接回收这个内存。
java.lang.ref
类 WeakReference<T>
java.lang.Object
java.lang.ref.Reference<T>
java.lang.ref.WeakReference<T>
public class WeakReference<T>
extends Reference<T>
弱引用对象,它们并不禁止其指示对象变得可终结,并被终结,然后被回收。弱引用最常用于实现规范化的映射。
public class Demo02_Weak {
@Test
public void test1(){
WeakReference<Dog> weak = new WeakReference<Dog>(new Dog());
//从引用里面获取这个对象
System.gc();
Dog dog = weak.get();
System.err.println("程序执行完成了:"+dog);
}
}
class Dog {
protected void finalize() {
System.err.println("被回收了 :"+this);
}
}
3:ajax
Asynchronized Javascrpt And XML - 异步的JS与XML/JSON文件。
功能:
异步的请求数据。浏览器开线程向后台发送请求。
页面的局部刷新。
组成部分:
1:XMLHttpRequest对象 脚本对象 核心对象,用于发送get/post请求。
2:XML文件,向服务器发送XML数据。
3:CSS 控制显示的样式。
4:JS 用于控制XHR对象发送请求。
1:如何创建XHR对象
<html>
<script type="text/javascript">
//1:声明xhr对象
var xhr = null;
//2:判断是否可以通过new的方式来创建xhr对象
//IE9以下的版本使用new ActiveXObject的方式来创建
//其他的浏览器都是通过new XMLHttpRequest的方式来创建
if(window.XMLHttpRequest){//IE10,FF,Chome,
xhr = new XMLHttpRequest();
console.log("IE10,ff,chrome");
}else{
xhr = new ActiveXObject("Microsoft.XMLHttp");
console.log("<IE9");
}
alert(xhr);
</script>
</html>
2:发送请示到后台,获取返回的字符串数据
readyState
0 (未初始化) | 对象已建立,但是尚未初始化(尚未调用open方法) |
1 (初始化) | 对象已建立,尚未调用send方法 |
2 (发送数据) | send方法已调用,但是当前的状态及http头未知 |
3 (数据传送中) | 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误, |
4 (完成) | 数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据 |
function _get() {
//1:声明访问的地址
var url = "/20160515/random";
//2:设置如何访问这个url
xhr.open("GET", url, true);//默认值就是异步
//3:注册服务器成功以后的回调函数
//
xhr.onreadystatechange = function() {
if(xhr.readyState==4){//判断是否接收到了数据
//判断服务器的状态
if(xhr.status==200){
//如果数据成功,就返回
var txt = xhr.responseText;
document.getElementsByName("name")[0].value=txt;
}else{
alert("失败:"+xhr.status);
}
}
};
//4:开始请求数据
xhr.send();
@WebServlet("/random")
public class RandomServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.err.println("请示过来的");
Random r = new Random();
int a = r.nextInt(100);
//输出文本
response.setContentType("text/plain;charset=UTF-8");
response.getWriter().print(a);
}
}