1 |
|
HIBERNATEDAOSUPPORT的GETHIBERNATETEMPLATE()的FIND方法大全
Dao实现类继承HibernateDaoSupport类,该类是抽象类,该类中有一个HibernateTemplate的属性,通过this.getHibernateTemplate()可获得一个HibernateTemplate类的对象。
1 | public class CustomerDaoImpl1 extends HibernateDaoSupport implements |
一些常用的方法列子:
find(String queryString);
示例:this.getHibernateTemplate().find(“from bean.User”);
返回所有User对象
二、find(String queryString , Object value);
示例:this.getHibernateTemplate().find(“from bean.User u where u.name=?”,“test”);
或模糊查询:this.getHibernateTemplate().find(“from bean.User u where u.name like ?”,“%test%”);
返回name属性值为test的对象(模糊查询,返回name属性值包含test的对象)
三、find(String queryString, Object[] values);
示例:String hql=“from bean.User u where u.name=? and u.password=?”
this.getHibernateTemplate().find(hql, new String[]{“test”,“123”});
返回用户名为test并且密码为123的所有User对象
四、findByExample(Object exampleEntity)
示例:
1 | User u=new User(); |
返回:用户名为bb密码为123的对象
五、findByExample(Object exampleEntity, intfristResults, int maxResults)
示例:
1 | User u=new User(); |
返回:满足用户名为bb密码为123,自start起共max个User对象。(对象从0开始计数)
六、findByNamedParam(String queryString , String paramName , Object value)
使用以下语句查询:
1 | String queryString =“select count(*) from bean.User u where u.name=:myName”; |
返回name为xiyue的User对象的条数
七、findByNamedParam(String queryString , String[] paramName , Object[] value)
示例:
1 | String queryString =“select count(*) from bean.User u where u.name=:myName and u.password=:myPassword”; |
返回用户名为xiyue密码为123的User对象
SPRINGMVC ,FREEMARKER页面自动静态化
1.maven 配置
1 | <dependency> |
三、建立模型文件(freemarker完全支持el表达式语言)
1 | <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”> |
四、编写视图解析器(FreeMarkerViewUtil.java),继承自org.springframework.web.servlet.view.freemarker.FreeMarkerView在这里对原类进行扩展
1 | package com.freemarker.Controller; |
访问:http://localhost:1010/springMVC_FreeMarker/home/index1.do,访问index1.do才会生成html文件,生成的html文件是根据@RequestMapping(“index1”)name决定的.
如果不需要生成静态化页面
1 | mav.addObject(“CREATE_HTML”, false); |
FREEMARKER
FreeMarker
概述
FreeMarker是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页、电子邮件、配置文件、源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
HTML静态化也是某些缓存策略使用的手段,对于系统中频繁使用数据库查询但是内容更新很小的应用,可以使用FreeMarker将动态页面静态化。
工作原理
模板:就是一份已经写好了基本内容,有着固定格式的文档,其中空出或者用占位符标识的内容,由使用者来填充,不同的使用者给出的数据是不同的。在模板中的占位符,在模板运行时,由模板引擎来解析模板,并采用动态数据替换占位符部分的内容。
FreeMarker与Web容器无关,即在Web运行时,它并不知道Servlet或HTTP。它不仅可以用作表现层的实现技术,而且还可以用于生成Html,XML,JSP或Java 等文件。
优缺点
优点
FreeMarker不支持Java脚本代码;所以可以彻底的分离表现层和业务逻辑;
提高开发效率。开发过程中,界面设计和开发人员可以并行工作;不必等待完成页面原形后,再开发程序;
开发过程中的人员分工更加明确。使用FreeMarker后,作为界面开发人员,只专心创建HTML文件、图像以及Web页面的其他可视化方面,不用理会数据;而程序开发人员则专注于系统实现,负责为页面准备要显示的数据。
缺点
生成静态的HTML页面后,数据更新可能不及时;
需要学习FreeMarker模版语言。而且FreeMarker中的变量必须要赋值,如果不赋值,那么就会抛出异常。想避免错误就要应用if/elseif/else 指令进行判断,如果对每一个变量都判断的话,那么则反而增加了编程的麻烦。FreeMarker的map限定key必须是string,其他数据类型无法操作。
第一个FreeMarker例子
搭建maven项目
搭建java项目即可。FreeMarker的依赖坐标为:
1 | <dependency> |
pom.xml的内容为:
1 | <project xmlns=“http://maven.apache.org/POM/4.0.0″; xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”; |
控制台输出
文件输出
模版
详见《FreeMarker_Manual_zh_CN.pdf》的第26页。
基本语法
一些常见的符号说明:
${ }插值;只能输出数值、日期或者字符串,其它类型不能输出。
<#freemarker命令
<#– 注释 –>
<@使用自定义命令
??是判断对象是否存在
?函数调用
命令
自定义对象输出
模版文件内容:
控制
语法:
1 | <#if condition> |
这里:
condition , condition2 等:表达式将被计算成布尔值。
关键字:gt :比较运算符“大于”;gte :比较运算符“大于或等于”;lt :比较运算符“小于”;lte :比较运算符“小于或等于”
循环
语法:
1 | <#list sequence as item> |
这里:
sequence :表达式将被算作序列或集合
item :循环变量(不是表达式)的名称
模板中可以如下遍历:
变量
语法:<#assign name=value>
示例:
1 | <#– 定义字符变量 –> |
语法:<#include path>
说明:path 参数可以是如 “foo.ftl” 和 “../foo.ftl” 一样的相对路径,或者是如”/foo.ftl” 这样的绝对路径。
示例:
创建一个copyright.ftl文件;内容如下:
1 | Copyright 2000-2017 ${me}<br> |
空值
在freemarker中对于空值必须手动处理。
在插值中处理空值:或者
${emp.name!} 表示name为空时什么都不显示
${emp.name!(“名字为空”)} 表示name为空时显示 名字为空
${(emp.company.name)!} 表示如果company对象为空则什么都不显示,!只用在最近的那个属性判断;所以如果遇上有自定义类型(导航)属性时,需要使用括号
${bool???string} 表示:首先??表示判断bool变量是否存在,存在返回true否则false,然后对返回的值调用其内置函数string
<#if str??> 表示去判断str变量是否存在,存在则true,不存在为false
模板示例:
1 | <#– ${emp.name!}的使用 –> |
列表与Map
列表
1 | <#assign nums = [1,2,3,4,5]> |
Map
Freemarker对于map的key而言,其key的类型必须为字符串。
处理map数据:
1 | <br> |
自定义命令macro
通过macro可以自定义命令,然后可以传递参数;在macro标签之间可以嵌套其它命令。另外;macro传递参数值时若参数有默认值则要把有默认值的参数放置在参数列表的最后。
<#– 第一个参数为命令的名称,是必须的;之后的为参数列表,可以添加多个 –>
自定义命令:
1 | <#macro sayHello name> |
REDIS常用命令
1.redis数据结构:
String(字符串类型)
list(链表)
hash(哈希表类型)
set(无序的集合)
sorted set(有序集合,缩写为zset)。
Redis的特点
1)高速读取数据(in-memory)
2)减轻数据库负担
3)有集合计算功能(优于普通数据库和同类别产品)
4)多种数据结构支持
redis 支持数据持久化和内存存储两种方式
Redis的数据类型和管理命令
1.Redis的String数据类型
string是redis最基本的类型
redis的string可以包含任何数据。包括jpg图片或者序列化的对象。
单个value值最大上限是1G字节。memcache单个value存储1M。
如果只用string类型,redis就可以被看作加上持久化特性(服务器重启之后,数据不丢失)的memcache
(1)set命令
该命令用于设置或者修改Redis中的键值(这个功能于Memcache的set有点类似) 命令语法:set 键名(key) 值(value)
例如:我们添加一个name=“itheima”的键值对。
例如:我们修改name为xiaoqian
注意:在redis当中默认使用set那么会永久存储在硬盘和内存当中,使用redis快照的方式进行存储的,redis的string类型没有所谓的过期时间命令,过期时间的命令属于服务器的key类型
(2)get命令
该命令用于获取Redis中key对应的string值,如果key不存在返回 nil,
命令语法:get 键名
获取一个已经存在的键名,可以得到该键名的值
如果一个键名不存在,那么获取该键名会返回nil
Redis的hash数据类型
(1)hset命令(hash set)
命令的功能:在哈希表中设置一个字段(field)和 一个字段的值(value)
命令格式: hset 哈希表的名称 字段(field) 字段值(value)
例如:存储一个名为Jay:star,字段为name,age和jober的哈希表数据,如下:
(2)hget命令
命令的功能:在一张指定的哈希表中获取字段的值,如果字段不存在那么将返回nil
命令格式: hget 哈希表的名称 字段(field)
例如:获取一张名为Jay:star的哈希表中获取姓名和年龄,代码如下所示:
以上使用hset和hget我们获取和设置哈希表的要一个一个的进行,比较没有效率,假设我们要一次设置多个哈希表的字段和值,那么我们应该怎么做呢?
(3)hmset命令
命令的功能:在哈希表中设置多个字段(field)和 多个字段的值(value)
命令格式: hmset 哈希表的名称 字段(field) 字段值(value)….
例子:存在一张名为itcast:gz的哈希表,字段有php,java,ui,php字段对应的值是laravel,java字段对应的值ssh,ui字段对应的值是photoshop
使用命令设置如下所示:
使用hgetall命令执行效果如下:
(4)hgetall命令
命令的功能:在哈希表获取所有的字段和值
命令格式: hgetall 哈希表的名称
例如:获取一个表名为Foods:Fruit的哈希表中的所有字段和值,代码如下所示:
hgetall Foods:Fruit
假设要获取Users:Jay,那么语句如下:
hset和hget的应用的范围如下:
①如果我们需要修改itcast:gz中的php为thinkphp3.2.3,我们应该如做呢?这时只能使用hset命令进行修改:
①如果我们需要修改itcast:gz中的php为thinkphp3.2.3,我们可以用hget直接查看php字段修改的结果:
3.Redis的list链表数据类型
链表数据结构中的栈:先进后出的特点,其原理图如下:
链表数据结构中的队列:先进先出
(1)lpush命令(跟栈相关)
命令的功能:在链表的栈中由头部压入一条数据
命令格式: lpush 链表的名称(栈名称) 值
命令如下:
例子:在一个名为list1的栈中压入数据one,two,three
以上分别在栈中头部压入的顺序为one,two,three,如下图所示
(2)rpush命令(跟队列相关)
命令的功能:在链表的队列中由尾部压入一条数据
命令格式: rpush 链表的名称(队列) 值
命令如下:
例子:在一个名为list2的队列中插入数据one,two,three
以上分别在队列中尾部压入的顺序为one,two,three,如下图所示
(3)lrange命令(跟队列和栈都相关,用于查询)
命令的功能:在链表的中获取一个范围的数据
命令格式: lrange 链表的名称 索引开始位置 索引结束位置(-1代表获取到全部)
例如:获取一个栈的所有数据,比如获取list1的链表中所有栈的数据
如图所示:
例如:获取一个队列list2的所有数据
例如:获取一个队列list2中开始位置为0,结束位置为1的数据
例如:获取一个栈list1中开始位置为1一直到最后的数据
lpop命令(与栈和队列相关)
命令的功能:弹出队列中的头部元素或者弹出栈中的头部元素,并且返回其值
命令格式: lpop 链表的名称
例子1:弹出list1栈中的头部元素
例子2:弹出list2队列中的头部元素
ltrim命令(一般用于队列操作比较多)
命令的功能:让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
命令格式: ltrim 链表的名称 开始的位置 结束的位置
现在有一个队列叫list3,其元素如下所示:
如果我们希望保存two,three,four区间的值,其他都删除,那么我应该怎么做?我们就需要使用ltrim命令:
我们知道two的索引为1,而four的索引为3,所以我们要保留的区间数据范围就索引1-3,因此编写命令如下:
如果我们需要把one,four,five保留其他都删除,是否可以做到呢?这样的区间保留队列是无法实现,所以这种需求是错误的
Redis的Set集合数据类型(无序集合)
在现实开发当中集合一般用于社交网站或者社交软件的朋友圈功能(例如:新浪微博好友圈),如下图所示:
在现实的社交网站开发当中存在着一个好友推荐的功能,这个就是把一个用户有朋友而另一个用户没有的朋友推荐,在redis当中这种功能可以使用集合中求差集的方法进行实现
差集的定义:一个集合存在某一个元素,而另外一个集合不存在的元素,该元素就属于两个集合的差集
交集的定义:一个集合和另外一个集合共同的元素,称为交集,在现实开发当中就是社交网站的共同好友功能
并集的定义:一个集合和另外一个集合进行合并然后去除重复的元素后所得到的结果就是并集,在实际开发当中并集的使用就是为了共享,游戏行业中的道具共享就是并集的结果
(1)sadd命令(set add)
命令的功能:在无序集合当中添加一个元素,该元素如果存在该元素不会被重复添加
命令格式: sadd 集合的名称 集合的元素
例子1:创建一个名为zsf的无序集合,含有元素杨过,小龙女,林朝英
例子2:创建一个名为lsf的无序集合,含有元素周伯通,杨过,洪七公
smembers命令
命令功能:查看一个无序集合中的所有的元素
命令格式: smembers [无序集合的名称]
例子:分别查看zsf和lsf的元素
sdiff命令(好友推荐功能)
命令的功能:以一个集合作为标准去求另外一个集合不存在的元素,我们称为差集(可以参考集合概念中差集的图片辅助理解)
命令格式: sdiff 作为标准的集合名称 求差集的集合名称
例子1:以张三作为标准求李四的差集
例子2:以李四作为标准求张三的差集
sinter命令
命令的功能:一个集合和另外一个集合共同的元素,我们称为交集(可以参考集合概念中交集的图片辅助理解)
命令格式: sinter 集合名称1 集合名称2
例子:求出张三和李四的共同好友
sunion命令
命令的功能:求出两个集合合并后所有的元素并去掉重复的元素的结果称为并集(可以参考集合概念中并集的图片辅助理解)
命令格式: sunion 集合名称1 集合名称2
比如:把张三的朋友和李四的朋友合并在一起进行群聊功能就可以使用以下命令:
scard命令
命令的功能:统计集合中的元素个数,并返回总数的整型值
命令格式: scard 集合名称
比如:希望知道张三或者李四有多少个好朋友,那么就可以使用该命令:
Redis的Zset集合数据类型(有序集合)
sorted set是set的一个升级版本,意大利文叫zset,在set的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset会自动重新按新的值调整顺序。有序列表值完成的是集合元素排序的功能,一般很少用于其他方向。
zadd 命令
命令功能:向有序集合中添加元素。如果该元素存在,则更新其顺序。
在zset当中序号是顺序,索引号是下标,注意区分
命令格式: zadd 集合名 序号 元素
比如:我们定义一个明星的社区,明星有排名,人气最高的明星排名第1杨幂,排名2鹿晗,排名3迪丽热巴,排序取决你的自定义顺序
1,2,3叫序号,不叫索引号,yangmi的序号是1,而索引号是0
zrange命令
命令功能:按序号升序(由小到大)获取有序集合中的内容
命令格式:zrange 集合名称 开始位置(索引) 结束位置(索引)(-1获取全部)
比如:获取stars当中所有有序集合中的元素,用升序进行排列
如果我们希望yangmi排dilireba之后,我们就需要修改yangmi的序号排名,比如让yangmi排第99位,依然使用zadd就可以完成这个功能,在redis中,如果zadd添加的元素已经存在,那么会更新当前元素的序号
比如:添加yangmi作为stars的元素,其序号为99,那么yangmi的序号就会被更新
修改后结果如下:
(3)zrevrange命令
命令功能:按序号降序(由大到小)获取有序集合中的内容。
命令格式:zrevrange 集合名称 开始位置(索引) 结束位置(索引)(-1获取全部)
比如:获取stars当中所有有序集合中的元素,用降序序进行排列
在一个叫做明星社区当中,有时候排名是按照粉丝数进行排名的,比如:邓超(4000),孙俪(3000),杨幂(1500),粉丝数作为排序的依据
五.Redis中与Key相关的命令
(1)keys * 命令
命令功能:返回当前数据库里面的键(key)
(2)exists命令
命令功能:判断一个键是否存在。
命令格式:exists 键名
比如:我们在网站中希望添加周杰伦的相关明星信息更新,但是我们需要直到周杰伦是否已经录入,这时我们可以使用exists命令
比如,我们查询林志玲的信息是否存在
如果返回0代表该键名不存在,如果返回1代表键名存在
(3)del
命令功能:删除指定的键(key),如果返回1代表删除键名成功,返回0代表删除失败
命令格式:del 键名
删除成功查看itcast:gz的键名则无法查询其内容
(4)expire
命令功能:设置键的有效期,如果不调用该命令设置键名,默认的情况下键名本身就是永远不过期。
命令格式:expire 键名 有效期(秒数)
比如:设置key为name的值15秒后过期,我们可以使用expire命令
如果时间到了,我们查询就返回nil:
如果我们现在设置了一个key在5分钟后过期(300秒),现在距离过期的时间还有多长,我们需要实时把握告诉用户,我们应该怎么做呢?只需用一个叫ttl的命令
(5)type
命令功能:返回一个键的数据类型
命令格式: type 键名
单点登录5-复习登录加自动登录(做客户端的登录)
- 简单流程
- username+password 登录(错误的话返回登录页,正确跳转到首页),在把user放在session,退出也是退出session.
- 加一个记住我
- 记住我,如果被选中,就把username_password存在cookie里,名字叫user.
- 下次在打开时,走一个过滤器,如果存在cookie-user,就利用cookie在登录一次。
- 注意点:加一个cookie.setpath(“/”);
单点登录4-CAS简单入门
1.为tomcat两个客户端安装证书
参考单点登录2
就不给图片了,安装成功。
2.tomcat下执行多个端口
1、配置运行tomcat 首先要配置java的jdk环境,这个就不在谢了 不懂去网上查查,这里主要介绍再jdk环境没配置好的情况下 如何配置运行多个tomcat
2、第一个tomcat: 找到”我的电脑” 里面的环境变量 , 添加”CATALINA_HOME”=”E:\apache-tomcat-6.0.29″ 这个时候第一个tomcat启动运行是没有问题的
3、接着开始配置第二个tomcat的:
增加环境变量CATALINA_HOME2,值为新的tomcat的地址;
增加环境变量CATALINA_BASE2,值为新的tomcat的地址;
4、找到第二个tomcat中的startup.bat文件,把里面的CATALINA_HOME改为CATALINA_HOME2
5、找到第二个tomcat中的catalina.bat,把里面的CATALINA_HOME改为CATALINA_HOME2,CATALINA_BASE改为CATALINA_BASE2
6、找到conf/server.xml文件 修改里面的内容如下(这一步说白了就是修改端口):
6.1、
6.2 、
6.3、
7、启动第二个tomcat,如果上面的配置没问题的话 这个时候是可以运行成功的!
疑点:1.在客户端的web.xml配置文件跳转不了正确回转地址(原因500,jdk路径不对)
1 | <filter-name>CASFilter</filter-name> |
单点登录-CAS登录原理说明.md
说明如下:
客户浏览器登录系统1,系统1重定向到认证系统并且带了server=shgdhghd.jsp,返回浏览器
浏览器写用户名,密码,后面认证系统去数据库找用户名,密码确认,如果对了就返回浏览器gc,还有ticket到浏览器。
浏览器在去系统一了,利用传给ticket去登录认证系统,没有经过数据库,直接返回user对象,登录系统1直接把user对象存到session中。
用户去登录系统2,携带了ticket,然后去登录认证系统,,利用传给ticket去登录认证系统,没有经过数据库,直接返回user对象,登录系统2直接把user对象存到session中。
用户退出后,就清理ticket,清理session.如果有用户同时登录,就看那个在时间的后面,清除session里的用户,登录到另一个地方。
JSON数组转对象LIST
使用的net.sf.json.JSONArray.
转化成list对象二句话。
server_data为String类型。
1 | JSONArray jsonarray = JSONArray.fromObject(server_data); |
单点登录3
我的百度云的cas单点登录的服务端和客户端,整理
cas-server里有modules文件,需要自己去看,找到war包
把他放入tomcat下的webapp,在配置一下c盘里的host,例如:192.168.1.137 wqc.com
做一个假的映射。启动tomcat.就可以访问这个地址了。
由于网上说的用户名和密码一致就可以登录的情况,做一个说明,由于版本不一样,我这里使用的cas-4.0.所以用户名为: casuser ,密码为:Mellon,就可以登录成功了
单点登录2-导入JAVA中的CACERTS证书库
在项目开发中,有时会遇到与SSL安全证书导入打交道的,如何把证书导入java中的cacerts证书库呢?
这是接着上仪表文档遇到的问题,因为在d:tomcat里生成的,而这个生成证书库是在c盘的jdk.
我的jdk安装在C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\security
这个目录,
开始 >> 运行 >> 输入cmd 进入dos命令行 >>进入上诉地址:C:\Program Files (x86)\Java\jdk1.8.0_144\jre\lib\security
敲入如下命令回车执行
1 | keytool -import -alias casserver -keystore cacerts -file D:\apache-tomcat-7.0.82\casserver.cer |
此时命令行会提示你输入cacerts证书库的密码,
这是java中cacerts证书库的默认密码:
你敲入changeit就行了。
成功后的图片
说明一下,因为我是在c:jdk里生成cascerts,并不是在上图,有不同的地方。
配置tomcat
4.服务端Tomcat配置
在制作完成密钥文件、证书文件、密钥库文件后即可进行服务端Tomcat的配置。打开$CATALINA_HOME/conf/server.xml
1 | <!–keystoreFile 生成的安全证书的位置–> |
说明:
port一般为8443或443,最常用的是443端口(https默认端口),
这样https方式访问的时候可以不加端口号(如:https://sso.demo.com/cas/login);
keystoreFile为tomcat目录下的密钥文件;
keystorePass为私钥密码;truststoreFile为生成的信任文件,
如果此处不指定则默认为$JAVA_HOME/jre/lib/security/cacerts文件;其它属性默认即可。
HIBERNATE–基础JAR包建立实体类
1.创建hibernate的基础jar包
1 | <project xmlns=“http://maven.apache.org/POM/4.0.0″; xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”; xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd”;> |
2.创建实体类
1 | public class Student { |
3.创建xml配置
1 | <?xml version=“1.0” encoding=“UTF-8”?> |
单点登录1-生成证书SSL
生成证书ssl
1.利用cmd生成证书
1 | keytool -genkey -alias casserver -keypass cas123 -keyalg RSA -keystore casserver.keystore -validity 365 |
说明:
-alias指定别名为casserver;
-keyalg指定RSA算法;
-keypass指定私钥密码;
-keystore指定密钥文件名称为casserver.keystore;
-validity指定有效期为365天。
另外提示输入密匙库口令应与-keypass指定的cas123相同;您的名字与姓氏fron.com是CAS服务器使用的域名(不能是IP,也不能是localhost),其它项随意填。
注意:
服务器上如果有多个JDK,请确认环境变量中的JDK路径为tomcat所使用的JDK,
如果不在环境变量中,也可切换到指定JDK的bin目录下执行命令;提示的输入keystore密码应与-keypass必须与指定的相同,
否则后面tomcat启动会报IO异常(Cannot recover key)。
命令执行成功后Server目录下多出casserver.keystore文件。
3)可以看到Tomcat 下面生成casserver.keystore
2.生成服务端证书casserver.cer
1)根据上面导出的casserver.keystore文件就可以生成casserver.cer文件,只需在原来的Serve的目录下面D:\Server\tomcat\下执行:
1 | keytool -export -alias casserver -storepass cas123 -file casserver.cer -keystore casserver.keystore |
说明:
-alias指定别名为casserver;
-storepass指定私钥为liuqizhi;
-file指定导出证书的文件名为casserver.cer;
-keystore指定之前生成的密钥文件的文件名。
注意:-alias和-storepass必须为生成casserver.keystore密钥文件时所指定的别名和密码,否则证书导出失败
后续:
导入证书文件到cacerts 密钥库文件
SPRING20–事务管理列子
1)事务本身是在数据库中,在dao。但是如果是银行转账的号,就要银行和用户一起改,如果不改,那就用户的钱减少,而银行的钱增加,这是不正常的。
在 Spring 中通常可以通过以下三种方式来实现对事务的管理:
(1)使用 Spring 的事务代理工厂管理事务
(2)使用 Spring 的事务注解管理事务
(3)使用 AspectJ 的 AOP 配置管理事务
spring事务管理api:
spring的事务管理,主要用到两个事务相关的接口
(1)事务管理器接口
事务管理器是 PlatformTransactionManager 接口对象。其主要用于完成事务的提交、回滚,及获取事务的状态信息。查看 SpringAPI 帮助文档:Spring 框架解压目录下的docs/javadoc-api/index.html。
(2)事务定义接口:
事务定义接口 TransactionDefinition 中定义了事务描述相关的三类常量:事务隔离级别、事务传播行为、事务默认超时时限,及对它们的操作。
A、定义了五个事务隔离级别常量:
这些常量均是以 ISOLATION_开头。即形如 ISOLATION_XXX。
DEFAULT:采用DB默认的事务隔离级别。MySql的默认为REPEATABLE_READ; Oracle默认为 READ_COMMITTED。
READ_UNCOMMITTED:读未提交。未解决任何并发问题。
READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
SERIALIZABLE:串行化。不存在并发问题。
例子:
Spring事务代码详解:
要求:实现模拟购买股票。存在两个实体:银行账户 Account 与股票账户 Stock。当要购买股票时,需要从 Account 中扣除相应金额的存款,然后在 Stock 中增加相应的股票数量。而在这个过程中,可能会抛出一个用户自定义的异常。异常的抛出,将会使两个操作回滚。
Step1:创建数据库表 account、stock
Step2:创建实体类 Account 与 Stock (略)
Step3:定义 Dao 接口 IAccountDao 与 IStockDao
1 | package com.tongji.dao; |
Step4:定义 Dao 实现类 AccountDaoImpl 与 StockDaoImpl
1 | package com.tongji.dao; |
Step5:定义异常类 StockException
1 | package com.tongji.beans; |
Step6:定义 Service 接口 IStockProcessService
1 | package com.tongji.service; |
Step7:定义 service 的实现类 StockProcessServiceImpl
1 | package com.tongji.service; |
Step8:定义Spring 配置文件
1 | <?xml version=”1.0″ encoding=”UTF-8″?> |
Step9:测试类
1 | package com.tongji.test; |
此配置文件没有采用事务管理,所以购买股票的时候,出现了数据库中账户金额减少了,但是股票数目没有增加的不一致情况。
使用 Spring 的事务代理工厂管理事务:
该方式是,需要为目标类,即 Service 的实现类创建事务代理。事务代理使用的类是TransactionProxyFactoryBean,该类需要初始化如下一些属性:
(1)transactionManager:事务管理器
(2)target:目标对象,即 Service 实现类对象
(3)transactionAttributes:事务属性设置
对于 XML 配置代理方式实现事务管理时,受查异常的回滚方式,程序员可以通过以下方式进行设置:通过“-异常”方式,可使发生指定的异常时事务回滚;通过“+异常”方式,可使发生指定的异常时事务提交。
修改Spring配置文件:
1 | <?xml version=”1.0″ encoding=”UTF-8″?> |
事务传播行为常量都是以 PROPAGATION_ 开头,形如 PROPAGATION_XXX。
REQUIRED:指定的方法必须在事务内执行。若当前存在事务,就加入到当前事务中;若当前没有事务,则创建一个新事务。这种传播行为是最常见的选择,也是Spring 默认的事务传播行为。
常量 TIMEOUT_DEFAULT 定义了事务底层默认的超时时限,及不支持事务超时时限设置的 none 值。
1 | <!– 生成事务代理 –> |
由于本项目使用的是 JDBC 进行持久化,所以使用 DataSourceTransactionManager 类作为事务管理器。
修改测试类:
1 | public void before() { |
使用 Spring 的事务注解管理事务:
通过@Transactional 注解方式,也可将事务织入到相应方法中。而使用注解方式,只需在配置文件中加入一个 tx 标签,以告诉 spring 使用注解来完成事务的织入。该标签只需指定一个属性,事务管理器。
修改Spring配置文件:
通过@Transactional 注解方式,也可将事务织入到相应方法中。而使用注解方式,只需在配置文件中加入一个 tx 标签,以告诉 spring 使用注解来完成事务的织入。该标签只需指定一个属性,事务管理器。
修改Spring配置文件:
1 | <!– 事务 –> |
修改 service 的实现类 StockProcessServiceImpl:
1 | package com.tongji.service; |
@Transactional 的所有可选属性如下所示:
propagation:用于设置事务传播属性。该属性类型为 Propagation 枚举,默认值为Propagation.REQUIRED。
isolation:用于设置事务的隔离级别。该属性类型为 Isolation 枚举,默认值为Isolation.DEFAULT。
readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为 boolean,默认值为 false。
timeout:用于设置本操作与数据库连接的超时时限。单位为秒,类型为 int,默认值为-1,即没有时限。
rollbackFor:指定需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
rollbackForClassName:指定需要回滚的异常类类名。类型为 String[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
noRollbackFor:指定不需要回滚的异常类。类型为 Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
noRollbackForClassName:指定不需要回滚的异常类类名。类型为 String[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。
需要注意的是,@Transactional 若用在方法上,只能用于 public 方法上。对于其他非public 方法,如果加上了注解@Transactional,虽然 Spring 不会报错,但不会将指定事务织入到该方法中。因为 Spring 会忽略掉所有非 public 方法上的@Transaction 注解。
若@Transaction 注解在类上,则表示该类上所有的方法均将在执行时织入事务。
使用 AspectJ 的 AOP 配置管理事务(重点):
使用 XML 配置事务代理的方式的不足是,每个目标类都需要配置事务代理。当目标类较多,配置文件会变得非常臃肿。使用 XML 配置顾问方式可以自动为每个符合切入点表达式的类生成事务代理。
修改spring的配置文件:
1 | <!– 事务 –> |
JETTY 插件的使用
jetty插件的安装
首先打开项目的pom.xml文件,然后找到build节点,在其中添加plugins节点,然后再添加如下的插件:
1 | <plugin> |
然后重新编译一下,就可以使用jetty插件了。使用mvn jetty:run就可以运行maven项目了。当前9.3.7是最新的jetty版本,以后会有更新的,请随时修改jetty的版本。
jetty插件的配置
在pom.xml中配置
在plugin节点下,添加configuration节点就可以配置jetty插件了。
1 | <configuration> |
idleTimeout。一次连接的最大空闲时间。
port。jetty服务器的端口号。
host。jetty服务器监听的地址。
scanIntervalSeconds。扫描进行热部署的间隔时间。
*
在jetty配置文件中配置
jetty插件也支持将jetty配置到相应的配置文件中,然后在pom.xml中引用这些配置文件。就像这样:
1 | <plugin> |
jetty插件的运行
jetty:run
jetty:run命令会直接使用源代码运行web程序,不将其打包成war文件。jetty插件会保证在运行前所有的类和资源都是最新的。如果你修改了代码,插件会自动重新部署。
jetty:run-war
run-war会先将程序打包成war文件然后再将其部署。如果有代码修改,会重新打包war文件并部署。
JAVA8-JAVA 8 日期时间 API
在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:1.java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。2.java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。 3.日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:
Local(本地) − 简化了日期时间的处理,没有时区的问题。
Zoned(时区) − 通过制定的时区处理日期时间。
新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。
参考工具类。下面写两个列子:
1 | LocalDateTime currentTime = LocalDateTime.now(); |
SPRING整合HESSIAN访问远程服务
1.1 Hessian简介
Hessian是一个轻量级的Web服务实现工具,它采用的是二进制协议,因此很适合发送二进制数据。它的一个基本原理就是把远程服务对象以二进制的方式进行发送和接收。
1.2 整合
1.2.1 概述
对于Hessian而言,有服务端和客户端,所以我们的整合也需要分服务端的整合和客户端的整合。服务端的整合是通过SpringMVC进行的,而客户端的整合则是通过Spring的bean进行的。
1.2.2 服务端整合(服务端需要实现他的方法)
基于客户端要调用服务端的远程服务,所以我们先来谈一下服务端的整合。Hessian的远程服务是基于接口的,所以我们要作为远程服务的实现类必须要实现一个接口。作为示例,这里我们建立一个叫hessianServer的web项目作为远程服务的服务端,在这个项目中我们建立一个叫做UserService的接口:
1 | package com.tiantian.hessianserver.service; |
然后建立一个它的实现类UserServiceImpl:
1 | package com.tiantian.hessianserver.service.impl; |
那么接下来我们要做的就是把UserServiceImpl作为一个远程服务进行发布,以致客户端能够进行访问。
首先我们需要在web.xml中配置一个SpringMVC的DispatcherServlet用于接收所有的Web服务请求,这里我们这样配置:
1 | <servlet> |
复制代码
可以看到我们这个DispatcherServlet会处理url为/api/service/*
的请求,通配符*
就对应着我们的处理器映射。
接下来就是在SpringMVC的配置文件中利用Hessian来定义我们的远程服务了,这是通过Spring提供的HessianServiceExporter来实现的。我们需要在SpringMVC的配置文件中定义一个类型为HessianServiceExporter的bean对象。该bean对象需要接收两个属性,一个是service属性,用于关联真正的service对象,另一个是serviceInterface属性,用于指定当前的服务对应的接口。HessianServiceExporter实现了HttpRequestHandler接口,当我们请求某一个远程服务的时候实际上请求的就是其对应的HessianServiceExporter对象,HessianServiceExporter会把请求的服务以二进制的方式返回给客户端。这里我们在SpringMVC的配置文件中这样定义:
Xml代码
1 | <bean id=“userService“ class=“com.tiantian.hessianserver.service.impl.UserServiceImpl“ /> |
注意看我们的HessianServiceExporter对应的bean的name是“/userService”,在SpringMVC的配置文件中,当一个bean的name是以“/”开始的时候Spring会自动对它进行BeanNameUrlHandlerMapping。所以这里相当于是我们把“/userService”映射到了HessianServiceExporter,根据上面的配置我们要请求这个远程服务的时候应该请求“/api/service/userService”。虽然说在Spring的配置文件中我们把bean的名称设为以“/”开始时Spring会自动对它进行一个beanName映射,但有一次不知道是哪里影响了,我这样使用的时候Spring没有对它进行自动映射,所以为了保险起见,这里我们最好自己指定一个BeanNameUrlHandlerMapping,代码如下所示:
Xml代码
1 | <bean class=“org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping“/> |
注意,因为是根据beanName来进行映射的,所以我们必须要给HessianServiceExporter bean对象指定name属性,而且其对应的name必须以“/”开头,这样我们的客户端才能访问到对应的服务。
1.2.3 客户端整合
对于客户端要使用远程的Hessian服务的,我们需要在Spring的配置文件中定义对应的org.springframework.remoting.caucho.HessianProxyFactoryBean bean对象。 HessianProxyFactoryBean对象需要指定两个属性,一个是serviceInterface属性,表示当前请求的远程服务对应的接口;另一个是serviceUrl属性,表示当前的远程服务对应的服务端请求地址。这里在客户端为了使用hessianServer定义的UserService服务,我们建立一个对应的hessianClient项目,在hessianClient中我们定义一个对应的UserService接口,这个接口的内容跟hessianServer中的UserService接口的内容是一样的。代码如下所示:
1 | package com.tiantian.hessianserver.service; |
之后我们就在当前Spring的配置文件中定义对应的HessianProxyFactoryBean对象。HessianProxyFactoryBean会根据指定的serviceInterface和serviceUrl属性返回一个serviceInterface对应的代理对象。这里我们的Spring配置文件这样定义:
1 | <?xml version=“1.0“ encoding=“UTF-8“?> |
可以看到我们通过HessianProxyFactoryBean定义了一个UserService对应的远程代理对象,之后我们就可以在我们的程序中把它作为一个普通的bean对象来使用这个UserService的代理对象了。这里我们定义以下测试代码:
Java代码
1 | package com.tiantian.hessianclient.test; |
之后我们启动我们的hessianServer,然后执行上面的测试程序,在服务端会输出如下内容:
在客户端会输出如下内容:
这说明我们已经成功地调用了远程服务UserService。
注:
1.Hessian不支持方法的重载,打个比方现在有一AddService,里面有一add(int a, int b)和一add(long a, long b)方法,然后我们把它发布为一个Hessian服务。那么当我们想要远程访问AddService的add方法时Hessian会报错,抛出异常
com.caucho.hessian.io.HessianProtocolException: ‘?’ is an unknown code
因为默认情况下它是不支持方法的重载,这个时候我们可以在客户端使用的时候新增属性overloadEnabled,值为true。如:
Xml代码
复制代码
1 | <?xml version=“1.0“ encoding=“UTF-8“?> |
MYSQL存储过程实现动态执行SQL
列子动态查询数据库一共几个表,一共多少条记录
1 | create PROCEDURE pc_test(in p_intdex int,in str varchar(100),OUT p_count int) |
—连接字符串构成完整SQL语句,动态SQL执行后的结果记录集,在MySQL中无法获取,因此需要转变思路将其放置到一个临时表中(注意代码中的写法)。一般写法如下:
1 | set p_ms:=CONCAT(“select count(*) into @p_cnt from “,d_tab_name); |
加参数查询的存储过程(改进版)
1 | create PROCEDURE pc_test(in p_intdex int,in str varchar(100),OUT p_count int) |
SPRING19—-自动代理生成器
上述中的aop编程15-18可能产生的问题:
1.若存在多个目标对象,就需要使用多次proxyFactoryBean创建多个代理对象,这会使配置文件变得臃肿,不便于管理。
2.用户真正想调用的是目标对象,而真正可以调用的却是代理对象,这不符合正常逻辑。
所以现在使用自动代理生成器。
自动代理生成器分成两种:
1.默认Advisor自动代理生成器
1 | <bean id=“ISomeService” class=“com.bean.service5.someServiceImpl”></bean> |
改为:
1 | <!– 生成代理对象 –> |
改为:
1 | <bean class=“org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator”></bean> |
DefaultAdvisorAutoProxyCreator引发的三个问题:
1.不能选择目标对象
2.不能选择切面类型,切面只能是advisor
3.不能选择advisor,所有advisor均将作为切面织入到目标方法
2.Bean名称自动代理生成器
1 | <bean id=“myAdvisor” class=“org.springframework.aop.support.RegexpMethodPointcutAdvisor”> |
SHARDING-JDBC单片分库分表-余数求膜
1、创建数据库
1 | create database sharding_0; |
接下来我们在两个库中创建相应的数据表,在两个库中分别进行如下SQL:
1 | SET FOREIGN_KEY_CHECKS=0; |
1、创建项目
1.1.配置pom.xml
2.创建数据库映射类
2.1 user类
2.2 student类
3.创建Mapper类
4.创建service类
5.创建service的实现类
6.创建分库逻辑
1.实现单片余数求膜 SingleKeyDatabaseShardingAlgorithm
7.创建分表逻辑
1.实现单片余数求膜 SingleKeyTableShardingAlgorithm
8.创建Mapper.xml
9.创建数据库连接类
10.创建spring配置文件
11.创建log4j.xml
12.、创建测试类ShardingJdbcMybatisTest
列子可以到工具类查看 分库分表实例