你更加崇拜大神,越说明你自学能力差

By admin in bet体育在线网址手机版 on 2018年10月13日

JDBC的突出用法:

旋即半天被是罗辑思维的《时间之情侣》跨年演讲刷屏,作为一个罗粉,我倒从没并不曾急着买会员听罗胖到底在提了数什么。那就是干吗吧?难道小六就当温馨同罗胖同牛了么?怎么可能!

  JDBC4.2经常因此接口及好像简介:

自之淡定在于:授人以鱼类勿若授人以渔,罗胖已把自家学习之方让于本人了呗。我既是现在和好会钓鱼,会起火了,那为什么非我先行自己试着做做也?虽然不必然好吃,但吃了自己之更夺尝尝尝了胖做的小菜,岂不是再度便宜自己之改善么?
 

    DriverManager:用于管理JDBC驱动的服务类,程序中采取该类的机要力量是取得Connection对象,该类包含如下方法:

因此我并不曾急在去听罗胖于出口啊,而是于进行相同蹩脚关于时间的底主题阅读。我怀念看看自己对日是哪些晓得的,然后重新任罗胖是怎样说的。

      public static synchronized Connection getConnection(String
url, String user, String  pass) throws
SQLException:该措施赢得url对许数据库的连天

因而今天自就是想跟大家拉家常这个话题:在此很神辈出、自媒体盛行的秋,我们怎样构建和谐之自学能力呢?

    Connection:代表数据库连接对象,每个Connection代表一个大体连接会话。想使顾数据库,必须优先得数据库连接,该接口的常用方法如下:

1、自学能力差会来什么问题?

有人会说,自学谁休会见什么,我们每天都当更那么多,做那么基本上事情,这些看到底,本身就是是上学啊。

比如体验,就是咱们看到的,听到的,感受及之。

试错的经过就是是咱们于劳作,在交往过程被温馨不停碰壁吸取到的经历啊。

还有观察,我们不是每日还于羁押大神们于站在互联网的风口浪尖的翻云覆雨么?

这些还是学习啊,既然我们每天都于求学,怎么就说咱们自学能力差啊?

咱俩事先来探视如果只有是恃经验,试错和考察进行上会发生什么问题:

缘何香蕉不可知动

管五不过猴子关在一个笼子里,上头有同等串香蕉实验人员作了一个自动装置。一旦侦测到产生猕猴要失去用香蕉,马上就会见发度喷向笼子,而当时五单纯猴子还见面雷同套湿。首先发出光猴子想去用香蕉,当然,结果虽是各级单猕猴还打湿了。

然后每只猴子在几乎潮的尝试后,发现可能如此。于是猴子们及一个共识:不要失去用香蕉,以避免给和喷到。后来实验人员拿中的同一独自猴子释放,换进去一只有新猴子A。这仅猴子A看到香蕉,马上想使错过用。结果,被外四单纯猴子海K了同一抛锚。因为另外四一味猴子认为猴子A会害他们于水淋到,所以杀他失去用香蕉,A尝试了几次,虽于于之满头包,依然没以到香蕉。当然,这五止猕猴就是无让和喷到。

后来尝试人员重新把同仅仅原本猴子释放,换上另外一不过新猴子B。这猴子B看到香蕉,也是焦心要失去用。当然,一如刚刚所生的事态,其他四只有猴子海K了B一间断。特别之是,那只A猴子打的特别拼命(这给老兵欺负新兵,或是媳妇熬成婆^O^)。B猴子试了几乎坏连续为打之深惨,只好作罢。

新兴日渐的一样就同就的,所有的故猴子还易成新猴子了,大家都未敢去动那香蕉。但是他们还不了解干什么,只晓得去动香蕉会被猴扁。

咱俩上学之时段不也常常如此呢?我们每日都以大众号受各种大神的宣导,去听各种讲座,线及以及线下的分享。那些站在聚光灯下的喻您他体会及之,他试错发现的,他观察到的。但是请问,你真正以为你收到了么?

即时既是是自学能力差带来的题目:我们就算如是一个初猴子一样,被废弃上了是笼子里。然后为告知“动香蕉就会见吃扁”。

紧接着上面的事例我们随后向生想,我立只猴子觉得无合拍啊,为什么“香蕉不能够动什么”,这时候我就是非以负原来的心得,试错和着眼的上学方式,我失去读书啊,我看当长辈猴子们就这香蕉文字以开及且勾了描写什么。一看,诶!原来是同救助傻逼人类实验者搞得糟实验!

      1.Statement createStatement() throws
SQLException:该法返回一个Statement对象。

2、自学主要控制的5单中心技术

      2.PreparedStatement prepareStatement(String sql) throws
SQLException:该办法返回预编译的Statement对象,即将SQL语句提交到数据库进行事先编译。

(1)提问能力:多问为什么,少问哪些怎么处置?

暨诸多同伴进行交互的上,更多的题材是本人哪、怎么处置。首先值得肯定之凡及时其间的绝大多数题目都是学习者从我问题出发的,但是我可看这些问题且全可以在知乎和百度解决。互联网的众人的分享与解答,如何、怎么惩罚的题目,你而相信这世界上有人肯定遇到跟你同的问题。所以,知乎百度上一定有人吗当讯问,也有人肯定都做出了对。

怎处置的问题百度一般还能缓解

那为什么而多咨询为何吧?你问问为何的时候,是曾经冲了某种事实了,在这种前提下,你已展开相同轮“什么是”和“怎么开”的品味了。准“我开了一部分什么事情,但是XXX,这是为什么吧?”

拉动在WHY去搜寻答案,你的读书会尤其有指向,也再高阶。

      3.CallableStatement prepareCall(String sql) throws
SQLException:该办法返回CallableStatement对象,该对象用于调用存储过程

(2) 检索能力

追寻能力可分成网络寻找和友爱之知识库检索:

A.网络检索:

说提问能力的当儿,我讲话到了为大家去百度豆瓣知乎自己搜索答案,很可惜,很多博年青人伴连基本的追寻能力且没有。搜索关键词该怎么形容?一个要词搜出来有几十万长长的数链接的早晚,如何压缩范围,更精确找到我思念只要之东西?

安用百度检索资料

网络寻能力就是设学会以检索条件。

B.自己的知识库检索:

还有一对略伙伴建立了和谐之云笔记,学会了争管网页,微博同公众号文章收集起来,可是若要是因此底下,却怎呢招来不至。公司电脑里的文本一律堆积,14年新年底年度计划上哪去了?一二三季度的总结报告呢?

友好之知识库检索,要学会成立标签。

学会成立标签

    上面三只措施都回用于执行SQL语句的Statement对象,PreparedStatement、CallableStatement是Statement的子类,只有获得了Statement之后才不过尽SQL语句。

(3)阅读理解能力

自学能力的基本功就是是读书理解能力。

我们切抛开啊精读和迅速阅读的撕逼,不管而用啊阅读方式,我们最终之目的是知情当下仍开,并且转化成我们内在的文化对么?

学及一个初知识是不可逆的,因为若如果学会了,就非可能将其忘记掉。那什么样才好不容易学会了接受掉了为?虽将上及之物用起来。

网络鸡汤为什么好喝可没用,是为若没办法通过鸡汤产生接下去的行动。吃得了如何,排出来什么样,这未尝接受,只是图个痛快而已。我们看《太子妃升职记》嗨翻了天,好玩是好游戏,但是针对学习吧没有啊用。

所以读书之知道,实际上是以阅读、理解还有增长学以致用,知行合一的步子。

赵周先生在他的《这样看就够了》里面涉及的RIA便签读书法,就是一个可知非常好增长协调阅读理解能力的方法。

图形来源于拆书帮

    除此之外,Connection还有如下几单用于控制工作的法门:

(4)写作能力

何以拿自学的学问以及阅历传播下,最好的法就是编著。

此处的写作不是恃虚构类的文艺,虽然那是一致种植更高阶的输出方式,但是对学这来说,怎将文化以及经历进行组织分类,排列组装,用结构性思维表达出来具体的场面,操作的步子和方,这才是咱得关注的

常见一点的话,我们写得每一样客报告,会议纪要都是创作。

怎样用结构思考力进行组织和发表,可以参照《金字塔原理》和李忠秋先生的《结构思考力》和《透过结构看世界》来学学。

控了描述的组织,落笔写下去的进程就是拿您写的思索导图,金字塔结构内容用文字表述出来要现已了。

      1.Savepoint setSavepoint():创建一个保存点

(5)实践能力

咱经常听到的星星只老长谈的歌词就是“学以致用”和“知行合一”。

我们了解了一致堆死道理,就是没失去用,就比如你本以念小六的及时篇稿子一样:

而会做出评论:嗯,还不凑;

也会抓住自己之思量:嗯,我之惯中好像真的是这样的吗;

接下来为,就从未有过然后了!最紧要之行进步调,我们没。

为什么我们走那么难以乎?

倘自身告诉你生一个黑法:若如遵循在自家此去做,立马明天就能找到对象

我还告知你任何一个方式:你如果每天坚持5分钟,一年晚您虽足以搜索到对象

心理学上早已通过大量试证明人另行易于选择满足这底大团结,为此除了非立马就可知奏效,否则我们累会选取拖延,不失去履行。所以我们重赞成被选7天学会XX、30分钟读毕一本书等等这样的方法论文章,因为其的周期异常短缺,很容易实现同证明。

既是这样,我们的闯荡好的尽能力的时段,就可尝尝把一个悠远的行动计划,拆解成一个一个有血有肉的钟点间段的行动

准《自控力》这本书是哈佛大学思维课程,作者建议我们用10到之时来提升自己之自控力,太久啦!那就拆除成10只1到家之时空,每七上失去实施里的一个流便吓哪。

      2.Savepoint setSavepoint(String
name):以指定名字创办一个保存点

3、开放-自学的情怀

开之情绪说起来容易,但是举行起来也很为难。因为自之心理是本着畅快的现状有发生只保护体制的。我现状干活很惬意,一切应付自如,我关系嘛要失去点哪些新东西为?

只是我们到底起敷衍不东山再起的时节吧?就以小六凡举行IT,但是有次和长官举报想上一个案例的当儿,效果平平,后来见到市场部的同事在介绍方案的时,很打动人,我虽于纪念,咦,他们之联络汇报技巧我能无克学一些呢?于是我就是暗中去念了无数市面与营销点的知。这些知识原来才是以我愕然,想尝试能不能够缓解自己的一个有血有肉的劳作障碍的,后来随即点的知却成为了自家开产品经理的一个优势。让自己学会站在商海和客户之角度区看到研发及召开的组成部分物。

为此,保持好奇心,产生链接,用开放的心情去学习。

丹尼尔.平克以他的《全新思维》一书中向我们来得了率领未来之六种为主的力:

《全新思维-决胜未来之六特别力量》

这些在信息时代常常为忽略与低估的力量,正是各个一样位愿意以未来拿走工作成功与促成个人希望的口用了解并升级的。

念的经过一样适用和当下六种植构思,让投机的情怀处于一个放之状态,针对身边的全部保持好奇心,产生重复多之链接

      3.void setTransactionIsolation(int
level):设置工作之隔断级别

4、自学的长河曲线

不少早晚咱们信心百倍满满地制订学习计划,但是也以接二连三很快放弃。是盖忽如其来的切肤之痛很容易会吃咱思想崩溃,心理及我们是匪绝喜欢跨预期的事物的,所以一律可是产生未如愿的地方,我们那个当然的哪怕见面挑放弃。

10000时理论告诉我们,学习的历程除了坚持,还待以坚持不懈的长河持续修正和调动自己。所以当自学的进程被,你要对读曲线来一个中坚的认识,给协调一个预料:嗯,一定会发生困难点,一定会发生瓶颈期的,但是这还怪正规,谁都见面遇见的,没干。

读曲线之良与现实性

      4.void rollback():回滚事务

结论:

其一时期,有一致居多人怀念变成这时代的自媒体,也时有发生平等森口每天还当时时刻刻被动接受这些自媒体转播的音讯。就如古时候的地主家一样,明明有雷同复眼睛,但是她们是匪读之,他们特意雇别人说写为好放。

使我们一直于吃别人做的小菜,那以初的等同年里,你想不思量尝同将,自己及菜市场去摘有食材,自己洗菜,配菜,自己绝对,然后自己油盐酱醋自己开一样鸣菜嫩?

自学能力,就是于此饭店遍地开花,口味奇特的期,尝试自己控制吃呦、怎么开、怎么吃的能力。

企望您的小菜上桌,记得喝小六品尝哈。

END.


打赏1片钱被六均等底肥胖基金捐款吧

原创版权,转载请私信

      5.void rollback(Savepoint
savepoint):将事情回滚到指定的保存点

      6.void setAutoCommit(boolean
autoCommit):关闭自动提交、打开工作

      7.void commit():提交业务

    Java7 为Connection新增了

      setSchema(String
schema)、getSchema()两独艺术:用于控制该Connection访问的数据库Schema

      setNetworkTimeout(Executor executor, int
milliseconds)、getNetworkTimeout()两只办法:用于控制数据库连接超时行为。

    Statement:用于实践SQL语句的家伙接口,常用方法如下:

      1.ResultSet executeQuery(String sql) throws
SQLException:该措施用于执行查询语句,并回到查询结果对应之ResultSet对象。该方法只能用于实践查询语句

      2.int executeUpdate(String sql) throws
SQLException:该措施用于实践DML(数据操作语言)语句,并回到给影响之行数;该方法吗只是用以实践DDL(数据定义

       语言)语句执行DDL语句以赶回回0

      3.boolean execute(String sql) throws
SQLException:该办法而实施外SQL语句。若实行后第一独结实也ResultSet对象,则归true;若实行后首先单结果吗受影

       响的行数或没有其他结果,则回false。

    Java7为Statement新增了closeOnCompletion()方法:若Statement执行了拖欠办法,则当有着因让该Statement的ResultSet关闭时,该Statement会自动关闭。

    Java7尚也Statement提供了isCloseOnCompletion()方法:用于判断该Statement是否打开了“closeOnCompletion”.

    Java8呢Statement新增了大多单重载的executeLargeUpdate()方法:这些主意相当给提高版的executeUpdate()方法,返回值类型为long,即当DML语句影响的记录条数超过

     Integer.MAX_VALUE时,就应有使用executeLargeUpdate()方法。

    PreparedStatement:预编译的Statement对象。PreparedStatement是Statement的子接口,它同意数据库预编译SQL语句(这些SQL语句日常含参数),以后每次只

     改变SQL命令的参数,避免数据库每次都亟待编译SQL语句,因此性能再好。相对于Statement而言,使用PreparedStatement执行SQL语句时,无需还传出SQL语句,只

     要也预编译的SQL语句流传参数数值即可。所以其比Statement多矣之类方法:

      1.void setXxx(int parameterIndex, Xxx
value):该办法根据传入参数值的类别不同,需要运用不同的点子。传入的价根据目录传为SQL语句被指定位置的参数。

  ResultSet:结果集对象。该目标涵盖访问查询结果的道,ResultSet可以通过列索引或列名获得列数据。它含有了如下常用方法来移动记录指针:

    1.void close():释放ResultSet对象。

    2.boolean absolute(int
row):将结果集的笔录指针动至第row行,若row是负数,则运动及倒数第row行。若移动后底笔录指针指于同漫长有效记录,则该方式返回true

    3.void
beforeFirst():将ResultSet的笔录指针定位及首行之前,这是ResultSet结果集记录指针的初步状态——记录指针的序幕位置在第一推行之前

    4.boolean
first():将ResultSet的笔录指针定位及首行。若移动继的记录指针指于同修中记录,则该办法返回true。

    5.boolean
previous():将ResultSet的笔录指针定位及齐一行。若移动继的记录指针指于同长中记录,则该法返回true。

    6.boolean
next():将ResultSet的记录指针定位及下一行,若移动继的记录指针指为平等长达中记录,则该法返回true。

    7.boolean
last():将ResultSet的记录指针定位及终极一推行,若移动继的记录指针指为同修中记录,则该方式返回true。 

    8.void afterLast():将ResultSet的笔录指针定位到结尾一行之后。

JDBC编程步骤:

  1.加载数据库让:

    通常采取Class类的forName()静态方法来加载驱动:

      Class.forName(driverClass);//driverClass就是数据库让类所对应的字符串。如:加载MySQL的叫代码

      Class.forName(“com.mysql.jdbc.Driver”);

  2.透过DriverManager获取数据库连接:

    //获取数据库连接

    DriverManager.getConnection(String url, String user, String
pass);//数据库URL、登录数据库的用户称以及密码。

    数据库URL通常以如下写法:

    jdbc:subprotocol:other stuff

    jdbc是一定的写法,subprotocol指定连接至一定数据库的让,other
stuff也不是稳的(由数据库定)

    MySQL数据库的URL写法如下:

    jdbc:mysql://hostname:port/databasename

  3.通过Connection对象创建Statement对象。有如下三单措施:

    1.createStatement():创建基本的Statement对象

    2.prepareStatement(String
sql):根据传入的SQL语句创建预编译的Statement对象

    3.prepateCall(String
sql):根据传入的SQL语句创建CllableStatement对象

  4.施用Statement执行SQL语句。有如下三只道:

    1.execute():可实施外SQL语句,但于麻烦

    2.executeUpdate():主要用来实施DML和DDL语句。执行DML语句返回给SQL语句影响的行数,执行DDL语句返回0

    3.executeQuery():只能实行查询语句,执行后返回代表询问结果的ResultSet对象

  5.操作结果集:

    若执行SQL语句是询问语句,则实行结果将返回一个ResultSet对象,该目标里保存了SQL语句询问的结果。程序可透过操作该ResultSet对象来取出查询结果:

      1.next()、previous()、first()、last()、beforeFirst()、afterLast()、absolute()等活动记录指针的不二法门

      2.getXxx()方法获得记录指针指向行、特定列的价。该法既而运列索引作为参数,也可是使列名作为参数。使用列索引作为参数性能再好,使用列名作为参数可

       读性更好

  6.回收数据库资源:

    包括关闭ResultSet、Statement和Connection等资源。

  下面程序简单示范了JDBC编程,并通过ResultSet获得结果集的进程:

图片 1图片 2

 1 drop database if exists select_test;
 2 create database select_test;
 3 use select_test;
 4 # 为了保证从表参照的主表存在,通常应该先建主表。
 5 create table teacher_table
 6 (
 7     # auto_increment:实际上代表所有数据库的自动编号策略,通常用作数据表的逻辑主键。
 8     teacher_id int auto_increment,
 9     teacher_name varchar(255),
10     primary key(teacher_id)
11 );
12 create table student_table
13 (
14     # 为本表建立主键约束
15     student_id int auto_increment primary key,
16     student_name varchar(255),
17     # 指定java_teacher参照到teacher_table的teacher_id列
18     java_teacher int,
19     foreign key(java_teacher) references teacher_table(teacher_id)
20 );
21 insert into teacher_table
22 values
23 (null , 'Yeeku');
24 insert into teacher_table
25 values
26 (null , 'Leegang');
27 insert into teacher_table
28 values
29 (null , 'Martine');
30 insert into student_table
31 values
32 (null , '张三' , 1);
33 insert into student_table
34 values
35 (null , '张三' , 1);
36 insert into student_table
37 values
38 (null , '李四' , 1);
39 insert into student_table
40 values
41 (null , '王五' , 2);
42 insert into student_table
43 values
44 (null , '_王五' , 2);
45 
46 insert into student_table
47 values
48 (null , null , 2);
49 insert into student_table
50 values
51 (null , '赵六' , null);

数据库建表语句

图片 3

将使(mysql-connector-java-5.1.30-bin.jar)放到java目录的产的jre/lib/ext/目录下面。或者以使得之路上加到classpath环境变量后面。

图片 4

图片 5图片 6

 1 import java.sql.Connection;
 2 import java.sql.DriverManager;
 3 import java.sql.Statement;
 4 import java.sql.ResultSet;
 5 
 6 public class ConnMySql{
 7     public static void main(String[] args) throws Exception{
 8         //1.加载驱动,使用反射知识,现在记住这么写
 9         Class.forName("com.mysql.jdbc.Driver");
10         try(
11             //2.使用DriverManager获取数据库连接
12             //其中返回的Connection就代表了Java程序和数据库的连接
13             //不同数据库的URL写法需要查询驱动文档,用户名、密码由DBA分配
14             Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/select_test", "root", "123456");
15             //3.使用Connection来创建一个Statement对象
16             Statement stmt = conn.createStatement();
17             //4.执行SQL语句
18             /*
19             Statement有三种执行SQL语句的方法:
20                 1.execute()可执行任何SQL语句-返回一个boolean值,若执行后第一个结果是ResultSet,则返回true,否则返回false
21                 2.executeQuery()执行select语句-返回查询到的结果集
22                 3.executeUpdate()用于执行DML语句-返回一个整数,代表被SQL语句影响的记录条数
23             */
24             ResultSet rs = stmt.executeQuery("select s.*, teacher_name"
25                 + " from student_table s , teacher_table t"
26                 + " where t.teacher_id = s.java_teacher")){
27                     //ResultSet有一系列的getXxx(列索引 | 列名)方法,用于获取记录指针
28                     //指向行、特定列的值,不断地使用next()将记录指针下移一行
29                     //若移动之后记录指针依然指向有效行,则next()方法返回true
30                     while(rs.next()){
31                         System.out.println(rs.getInt(1) + "\t"
32                             + rs.getString(2) + "\t"
33                             + rs.getString(3) + "\t"
34                             + rs.getString(4));
35                     }
36                 }
37     }
38 }

View Code

图片 7

 执行SQL语句之办法:

  使用Java8初长的executeLargeUpdate()方法执行DDL和DML语句:

  使用statement执行DDL和DML语句之步调及执行日常查询语句的步子基本相似,区别在实施了DDL语句后返回值为0,执行了DML语句后返回值为蒙受震慑之笔录条数。

  MySQL暂未支持executeLargeUpdate()方法。所以我们使用executeUpdate()方法。

  下面的顺序并不曾一直把数据库连接信息写于代码中,而是以一个mysql.ini文件(就是properties文件)来保存数据库连接信息,这是较成熟之做法——当用将应用程

   序从开条件移植到生产条件时,无需修改源代码,只需要改mysql.ini配置文件即可:

 mysql.ini文件内容:

图片 8

mysql.ini和ExecuteDDL.java文件所加大位置:

图片 9

图片 10图片 11

 1 import java.io.FileInputStream;
 2 import java.util.Properties;
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.Statement;
 6 
 7 
 8 public class ExecuteDDL{
 9     private String driver;
10     private String url;
11     private String user;
12     private String pass;
13     public void initParam(String paramFile) throws Exception{
14         //使用Properties类来加载属性文件
15         Properties props = new Properties();
16         props.load(new FileInputStream(paramFile));
17         driver = props.getProperty("driver");
18         url = props.getProperty("url");
19         user = props.getProperty("user");
20         pass = props.getProperty("pass");
21     }
22     
23     public void createTable(String sql) throws Exception{
24         //加载驱动
25         Class.forName(driver);
26         try(
27             //获取数据库连接
28             Connection conn = DriverManager.getConnection(url, user, pass);
29             //使用Connection来创建一个Statement对象
30             Statement stmt = conn.createStatement()){
31                 //执行DDL语句,创建数据表
32                 stmt.executeUpdate(sql);
33             }
34     }
35     
36     public static void main(String[] args) throws Exception{
37         ExecuteDDL ed = new ExecuteDDL();
38         ed.initParam("mysql.ini");
39         ed.createTable("create table jdbc_test "
40             + "( jdbc_id int auto_increment primary key, "
41             + "jdbc_name varchar(255), "
42             + "jdbc_desc text);");
43             System.out.println("------建表成功------");
44     }
45 }

View Code

图片 12

  使用executeUpdate()方法执行DML语句:

    和方面程序的步骤是一模一样的,只不过程序代码需要改:

图片 13图片 14

 1 import java.io.FileInputStream;
 2 import java.util.Properties;
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.Statement;
 6 
 7 public class ExecuteDML{
 8     private String driver;
 9     private String url;
10     private String user;
11     private String pass;
12     
13     public void initParam(String paramFile) throws Exception{
14         Properties props = new Properties();
15         props.load(new FileInputStream(paramFile));
16         driver = props.getProperty("driver");
17         url = props.getProperty("url");
18         user = props.getProperty("user");
19         pass = props.getProperty("pass");
20     }
21     
22     public int insertData(String sql) throws Exception{
23         //加载驱动
24         Class.forName(driver);
25         try(
26             //获取数据库连接
27             Connection conn = DriverManager.getConnection(url, user, pass);
28             //使用Connection来创建一个Statement对象
29             Statement stmt = conn.createStatement()){
30                 //执行SQL语句,返回受影响的记录条数
31                 return stmt.executeUpdate(sql);
32             }
33     }
34     
35     public static void main(String[] args) throws Exception{
36         ExecuteDML ed = new ExecuteDML();
37         ed.initParam("mysql.ini");
38         int result = ed.insertData("insert into jdbc_test(jdbc_name,jdbc_desc)"
39             + "select s.student_name , t.teacher_name "
40             + "from student_table s , teacher_table t "
41             + "where s.java_teacher = t.teacher_id;");
42         System.out.println("------系统中一共有" + result + "条记录受影响------");
43     }
44 }

View Code

图片 15

图片 16

  使用execute()方法执行SQL语句:

    Statement的execute()方法几乎可实施外SQL语句,但其执行SQL语句比较费心,通常没有必要使用execute()方法来实施SQL语句。

    使用execute()方法执行SQL语句之归值只有是boolean值,它标志执行该SQL语句是否回了ResultSet对象,Statement提供了如下两独方法来得到执行结果:

      1.getResultSet():获取该Statement执行查询语句子所返的ResultSet对象

      2.getUpdateCount():获取该Statement执行DML语句所影响的记录行数。

    下面程序示范了利用Statement的execute()方法来实施任意的SQL语句:

图片 17图片 18

 1 import java.util.Properties;
 2 import java.io.FileInputStream;
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.Statement;
 6 import java.sql.ResultSet;
 7 import java.sql.ResultSetMetaData;
 8 
 9 public class ExecuteSQL{
10     private String driver;
11     private String url;
12     private String user;
13     private String pass;
14     
15     public void initParam(String paramFile) throws Exception{
16         //使用Properties类来加载属性文件
17         Properties props = new Properties();
18         props.load(new FileInputStream(paramFile));
19         driver = props.getProperty("driver");
20         url = props.getProperty("url");
21         user = props.getProperty("user");
22         pass = props.getProperty("pass");
23     }
24     
25     public void executeSql(String sql) throws Exception{
26         //加载数据库驱动
27         Class.forName(driver);
28         try(
29             //获取数据库连接
30             Connection conn = DriverManager.getConnection(url, user, pass);
31             //通过Connection创建一个Statement
32             Statement stmt = conn.createStatement()){
33                 //执行SQL语句,返回boolean值表示是否包含ResultSet
34                 boolean hasResultSet = stmt.execute(sql);
35                 //若执行后有ResultSet结果集
36                 if(hasResultSet){
37                     try(
38                         //获取结果集
39                         ResultSet rs = stmt.getResultSet()){
40                             //ResultSetMetaData是用于分析结果集的元数据接口
41                             ResultSetMetaData rsmd = rs.getMetaData();
42                             int columnCount = rsmd.getColumnCount();
43                             //迭代输出ResultSet对象
44                             while(rs.next()){
45                                 //依次输出每列的值
46                                 for(int i = 0; i < columnCount; i++){
47                                     System.out.print(rs.getString(i + 1) + "\t");
48                                 }
49                                 System.out.print("\n");
50                             }
51                         }
52                 }else{
53                     System.out.println("该SQL语句影响的记录有" + stmt.getUpdateCount() + "条");
54                 }
55             }
56     }
57     
58     public static void main(String[] args) throws Exception{
59         ExecuteSQL es = new ExecuteSQL();
60         es.initParam("mysql.ini");
61         System.out.println("------执行删除表的DDL语句------");
62         es.executeSql("drop table if exists my_test");
63         System.out.print("------执行建表的DDL语句------");
64         es.executeSql("create table my_test"
65             + "(test_id int auto_increment primary key, "
66             + "test_name varchar(255))");
67         System.out.println("------执行插入数据的DML语句------");
68         es.executeSql("insert into my_test(test_name) "
69             + "select student_name from student_table");
70         System.out.println("------执行查询数据的查询语句------");
71         es.executeSql("select * from my_test");
72     }
73 }

View Code

图片 19

  从结果看,执行DDL语句显示为影响记录条数;执行DML显示插入、修改、删除的记录条数;执行查询语句子可以出口查询结果。

  上面程序获取的SQL执行结果是从来不因各列的数据类型调用相应的getXxx()方法,而是一直动用getString()方法来得到值,这是足以的。

  ResultSet的getString()方法几乎可以收获除了Blob之外的随意档次列的价,因为有的数据类型都足以自行转换成为字符串类型。

  使用PreparedStatement执行SQL语句:

    若常要数实践同一久组织相似之SQL语句,如下两长达:

    insert into student_table values(null, ‘张三’, 1);

    insert into student_table values(null, ‘李四’, 2);

    对于当下简单长语句,它们组织相似,只是履行插入时插入的价不同而已。对于这种情形,可以动用占位符(?)参数的SQL语句来代表它:

    insert into student_table values(null, ?, ?);

    JDBC提供了PreparedStatement接口,它是Statement的子接口。它可拓展预编译SQL语句,预编译后的SQL语句被储存在PreparedStatement对象被,然后可以应用该

     对象往往快捷地执行该语句。使用PreparedStatement比使用Statement的效率要后来居上。

    创建PreparedStatement对象下Connection的prepareStatement()方法,该方法需要传入一个SQL字符串,该SQL字符串可以包括占位符参数,如下:

      //创建一个PreparedStatement对象

      pstmt = conn.prepareStatement(“insert into student_table
values(null,?,1)”);

    PreparedStatement也供了execute()、executeUpdate()、executeQuery()三独道来推行SQL语句,不过当下三个艺术无论需参数,因为PreparedStatement已经储存了优先

     编译的SQL语句。

    使用PreparedStatement预编译SQL语句时,该SQL语句可以带动占位符参数,因此在实践SQL语句之前务必为这些参数传入参数值,PreparedStatement提供了扳平多重

     的setXxx(int index, Xxx value)方法来传参数值。

 下面程序示范了采用Statement和PreparedStatement分别插入100长记下的相比。:

图片 20图片 21

 1 import java.io.FileInputStream;
 2 import java.util.Properties;
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.PreparedStatement;
 6 import java.sql.Statement;
 7 
 8 public class PreparedStatementTest{
 9     private String driver;
10     private String url;
11     private String user;
12     private String pass;
13     
14     public void initParam(String paramFile) throws Exception{
15         //使用Properties类加载属性文件
16         Properties props = new Properties();
17         props.load(new FileInputStream(paramFile));
18         driver = props.getProperty("driver");
19         url = props.getProperty("url");
20         user = props.getProperty("user");
21         pass = props.getProperty("pass");
22         //加载驱动
23         Class.forName(driver);
24     }
25     
26     public void insertUseStatement() throws Exception{
27         long start = System.currentTimeMillis();
28         try(
29             //获取数据库连接
30             Connection conn = DriverManager.getConnection(url, user, pass);
31             //使用Connection来创建一个Statement对象
32             Statement stmt = conn.createStatement())
33             {
34                 //需要使用100条SQL语句来插入100条记录
35                 for(int i = 0; i < 100; i++){
36                     stmt.executeUpdate("insert into student_table values("
37                         + "null,'姓名" + i + "', 1)");
38                 }
39                 System.out.println("使用Statement费时:"
40                     + (System.currentTimeMillis() - start));
41             }
42     }
43     
44     public void insertUsePrepare() throws Exception{
45         long start = System.currentTimeMillis();
46         try(
47             //获取数据库连接
48             Connection conn = DriverManager.getConnection(url, user, pass);
49             //使用Connection来创建一个PreparedStatement对象
50             PreparedStatement pstmt = conn.prepareStatement("insert into student_table values(null,?,1)"))
51             {
52                 //100次为PreparedStatement的参数设值,就可以插入100条记录
53                 for(int i = 0; i < 100; i++){
54                     pstmt.setString(1, "姓名" + i);
55                     pstmt.executeUpdate();
56                 }
57                 System.out.println("使用PreparedStatement费时:" + (System.currentTimeMillis() - start));
58             }
59     }
60     
61     public static void main(String[] args) throws Exception{
62         PreparedStatementTest pt = new PreparedStatementTest();
63         pt.initParam("mysql.ini");
64         pt.insertUseStatement();
65         pt.insertUsePrepare();
66     }
67 }

View Code

图片 22

  从地方的结果看,PreparedStatement耗时少于Statement。

  使用PreparedStatement还生一个充分好的用意——用于防止SQL注入。

下面为一个略的记名窗口也例来介绍这种SQL注入的结果:

图片 23图片 24

 1 import java.sql.Connection;
 2 import java.sql.DriverManager;
 3 import java.sql.Statement;
 4 import java.sql.ResultSet;
 5 import java.util.Properties;
 6 import java.io.FileInputStream;
 7 import java.awt.*;
 8 import javax.swing.*;
 9 
10 
11 public class LoginFrame{
12     private final String PROP_FILE = "mysql.ini";
13     private String driver;
14     //url是数据库的服务地址
15     private String url;
16     private String user;
17     private String pass;
18     //登录界面的GUI组件
19     private JFrame jf = new JFrame("登录");
20     private JTextField userField = new JTextField(20);
21     private JTextField passField = new JTextField(20);
22     private JButton loginButton = new JButton("登录");
23     
24     public void init() throws Exception{
25         Properties connProp = new Properties();
26         connProp.load(new FileInputStream(PROP_FILE));
27         driver = connProp.getProperty("driver");
28         url = connProp.getProperty("url");
29         user = connProp.getProperty("user");
30         pass = connProp.getProperty("pass");
31         //加载驱动
32         Class.forName(driver);
33         //为登录按钮添加事件监听器
34         loginButton.addActionListener(e -> {
35             //登录成功则显示“登录成功”
36             if(validate(userField.getText(), passField.getText())){
37                 JOptionPane.showMessageDialog(jf, "登录成功");
38             }else{
39                 //否则显示“登录失败”
40                 JOptionPane.showMessageDialog(jf, "登录失败");
41             }
42         });
43         jf.add(userField, BorderLayout.NORTH);
44         jf.add(passField);
45         jf.add(loginButton, BorderLayout.SOUTH);
46         jf.pack();
47         jf.setVisible(true);
48     }
49     
50     private boolean validate(String userName, String userPass){
51         //执行查询的SQL语句
52         String sql = "select * from jdbc_test "
53             + "where jdbc_name='" + userName
54             + "' and jdbc_desc='" + userPass + "';";
55         System.out.println(sql);
56         try(
57         Connection conn = DriverManager.getConnection(url, user, pass);
58         Statement stmt = conn.createStatement();
59         ResultSet rs = stmt.executeQuery(sql))
60         {
61             //若查询的ResultSet里有超过一条的记录,则登录成功
62             if(rs.next()){
63                 return true;
64             }
65         }catch(Exception e){
66             e.printStackTrace();
67         }
68         
69         return false;
70     }
71     
72     public static void main(String[] args) throws Exception{
73         new LoginFrame().init();
74     }
75 }

View Code

签到界面:

图片 25

报到成功界面:

图片 26

图片 27

失掉数据库被查询是否是用户以及密码,执行的SQL语句。从上面的结果好看来,我们于报到用户称中输入‘
or true or ’时,竟然为登录成功了。原因即发出以履行之SQL语句上。

若是密码以及用户也空,但是where后底尺度永远为真正,这便告知软件,数据库被存在拖欠用户,可以登录。

  将上面的validate()方法变成采取PreparedStatement来施行验证,而休是直动用Statement:

图片 28图片 29

 1 import java.sql.Connection;
 2 import java.sql.DriverManager;
 3 import java.sql.PreparedStatement;
 4 import java.sql.ResultSet;
 5 import java.util.Properties;
 6 import java.io.FileInputStream;
 7 import java.awt.*;
 8 import javax.swing.*;
 9 
10 
11 public class LoginFrame{
12     private final String PROP_FILE = "mysql.ini";
13     private String driver;
14     //url是数据库的服务地址
15     private String url;
16     private String user;
17     private String pass;
18     //登录界面的GUI组件
19     private JFrame jf = new JFrame("登录");
20     private JTextField userField = new JTextField(20);
21     private JTextField passField = new JTextField(20);
22     private JButton loginButton = new JButton("登录");
23     
24     public void init() throws Exception{
25         Properties connProp = new Properties();
26         connProp.load(new FileInputStream(PROP_FILE));
27         driver = connProp.getProperty("driver");
28         url = connProp.getProperty("url");
29         user = connProp.getProperty("user");
30         pass = connProp.getProperty("pass");
31         //加载驱动
32         Class.forName(driver);
33         //为登录按钮添加事件监听器
34         loginButton.addActionListener(e -> {
35             //登录成功则显示“登录成功”
36             if(validate(userField.getText(), passField.getText())){
37                 JOptionPane.showMessageDialog(jf, "登录成功");
38             }else{
39                 //否则显示“登录失败”
40                 JOptionPane.showMessageDialog(jf, "登录失败");
41             }
42         });
43         jf.add(userField, BorderLayout.NORTH);
44         jf.add(passField);
45         jf.add(loginButton, BorderLayout.SOUTH);
46         jf.pack();
47         jf.setVisible(true);
48     }
49     
50     private boolean validate(String userName, String userPass){
51         //执行查询的SQL语句
52         String sql = "select * from jdbc_test "
53             + "where jdbc_name='" + userName
54             + "' and jdbc_desc='" + userPass + "';";
55         System.out.println(sql);
56         try(
57         Connection conn = DriverManager.getConnection(url, user, pass);
58         PreparedStatement pstmt = conn.prepareStatement("select * from jdbc_test where jdbc_name=? and jdbc_desc=?;"))
59         {
60             pstmt.setString(1, userName);
61             pstmt.setString(2, userPass);
62             try(
63                 ResultSet rs = pstmt.executeQuery())
64                 {
65                     //若查询的ResultSet里有超过一条的记录,则登录成功
66                     if(rs.next()){
67                         return true;
68                     }
69                 }
70         }catch(Exception e){
71             e.printStackTrace();
72         }
73         
74         return false;
75     }
76     
77     public static void main(String[] args) throws Exception{
78         new LoginFrame().init();
79     }
80 }

View Code

签到界面:

图片 30

报到失败界面:

图片 31

图片 32

  从结果受到可以看出,把用户被的’ or true or
‘添加至了jdbc_name的后面,避免的SQL注入。

  使用PreparedStatement比采用Statement多矣如下三独好处:

    1.PreparedStatement预编译SQL语句,性能再好

    2.PreparedStatement无论需“拼接”SQL语句,编程更简明

    3.PreparedStatement得防SQL注入,安全性更好

  基于上面三点,通常推荐避免下Statement来实施SQL语句,改也下PreparedStatement执行SQL语句。

  使用PreparedStatement执行带来占位符参数的SQL语句时,SQL语句被之占位符参数只能代替普通值,不克代表表名、列名等数据库对象,也未可知替代的insert、select等要字

  使用CallableStatement调用存储过程:

    图片 33

  进入一个数据库被,执行方的通令。delimiter
//将MySQL的讲话结束符改为对斜线(\\),这样便可当开立存储过程被运用分号作为分隔符(MySQL默认使用分号作为报告

   句子结束符)。记得执行完毕上面命令还将扫尾符改为分行。上面命令创建了名吧add_pro的存储过程,该存储过程包含三个参数:a
b是流传参数,sum使用out修饰,是传

   参数

  调用存储过程采用CallableStatement,可经Connection的prepareCall()方法来创造CallableStatement对象,创建该目标时需传入调用存储过程的SQL语句。

  调用存储过程的SQL语句格式:{call 过程叫(?, ?, …, ?)}若下所示:

    //使用Connection来创造一个CallableStatement对象

    cstmt = conn.prepareCall(“{call add_pro(?, ?, ?)”});

  存储过程有传参数,也出传出参数。Java程序必须为这些参数传入值,可经过CallableStatement的setXxx()方法吧流传参数设置值;传出参数就是Java程序可以通过该参数

   获取存储过程里的值,CallableStatement需要调用registerOutParameter()方法来报该参数。如下所示:

    //注册CallableStatement的老三个参数是int类型

    cstmt.registerOutParameter(3, Types.INTEGER);

  经过地方步骤,就好调用CallableStatement的execute()方法来实施存储过程了,执行完毕后通过CallableStatement对象的getXxx(int
index)方法来得到指定传出参数的价值。

图片 34图片 35

 1 import java.util.Properties;
 2 import java.io.FileInputStream;
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.CallableStatement;
 6 import java.sql.Types;
 7 
 8 public class CallableStatementTest{
 9     private String driver;
10     private String url;
11     private String user;
12     private String pass;
13     
14     public void initParam(String paramFile) throws Exception{
15         //使用Properties类来加载属性文件
16         Properties props = new Properties();
17         props.load(new FileInputStream(paramFile));
18         driver = props.getProperty("driver");
19         url = props.getProperty("url");
20         user = props.getProperty("user");
21         pass = props.getProperty("pass");
22     }
23     
24     public void callProcedure()throws Exception{
25         //加载驱动
26         Class.forName(driver);
27         try(
28             //获取数据库连接
29             Connection conn = DriverManager.getConnection(url, user, pass);
30             //使用Connection来创建一个CallableStatement对象
31             CallableStatement cstmt = conn.prepareCall("{call add_pro(?,?,?)}")
32         ){
33             cstmt.setInt(1, 4);
34             cstmt.setInt(2, 5);
35             //注册CallableStatement的第三个参数时int类型
36             cstmt.registerOutParameter(3, Types.INTEGER);
37             //执行存储过程
38             cstmt.execute();
39             //获取并输出存储过程传出的参数的值
40             System.out.println("执行结果是:" + cstmt.getInt(3));
41         }
42     }
43     
44     public static void main(String[] args) throws Exception{
45         CallableStatementTest ct = new CallableStatementTest();
46         ct.initParam("mysql.ini");
47         ct.callProcedure();
48     }
49 }

View Code

图片 36

   管理结果集:

    JDBC使用ResultSet来封装执行查询得到的查询结果,后透过活动ResultSet的笔录指针来取出结果集内容。除此之外,JDBC还同意ResultSet来更新记录,并提供

     ResultSetMetaData来得到ResultSet对象的连带信息

    可滚动、可更新的结果集:

      使用absolute()、previous()、afterLast()等办法自由活动记录指针的ResultSet被誉为可滚动的结果集。

      以默认方式打开的ResultSet是不行更新的,若要创建而更新的ResultSet,则要在创造Statement或PreparedStatement时传出额外的参数。

      Connection在创立Statement或PreparedStatement时只是额外传入如下两独参数:

       1.resultSetType:控制ResultSet的门类,该参数可以获取如下三只价值:

        1.ResultSet.TYPE_FORWARD_ONLY:该常量控制记录指针只能上移动。

        2.ResultSet.TYPE_SCROLL_INSENSITIVE:该常量控制记录指针可以自由移动(可滚动结果集),但底层数据的改不会见潜移默化ResultSet的情节

        3.ResultSet.TYPE_SCROLL_SENSITIVE:该常量控制记录指针可随便移动(可滚动结果集),而且底层数据的变更会潜移默化ResultSet的内容

        TYPE_SCROLL_INSENSITIVE、TYPE_SCROLL_SENSITIVE两独常量的作用要底层数据库让之支持,对于有头数据库让来说,这点儿只连从未尽怪的区分

       2.resultSetConcurrency:控制ResultSet并发类型,该参数可以收如下两只价:

        1.ResultSet.CONCUR_READ_ONLY:该常量指示ResultSet是仅仅念之面世模式(默认)。

        2.ResultSet.CONCUR_UPDATABLE:该常量指示ResultSet是不过更新的产出模式。

      下面代码通过这片只参数创建了一个PreparedStatement对象,由该目标生成的ResultSet对象将凡可滚动、可更新的结果集:

      //使用Connection创建一个PreparedStatement对象

      //传入控制结果集而滚动、可更新的参数:

      pstmt = conn.prepareStatement(sql,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

      需要指出的是,可更新的结果集还得满足如下两只尺码:

        1.所出数量还应当来自一个发明

        2.选出的数量集必须包含主键列

      可调用ResultSet的updateXxx(intcolumnIndex, Xxx
value)方法来改记录指针所负记录、特定列的值,最后调用ResultSet的updateRow()方法来交付修改。

  下面程序示范了这种创建而滚动、可更新的结果集的方:

图片 37图片 38

 1 import java.util.Properties;
 2 import java.io.FileInputStream;
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.PreparedStatement;
 6 import java.sql.ResultSet;
 7 
 8 public class ResultSetTest{
 9     private String driver;
10     private String url;
11     private String user;
12     private String pass;
13     public void initParam(String paramFile) throws Exception{
14         //使用Properties类加载属性文件
15         Properties props = new Properties();
16         props.load(new FileInputStream(paramFile));
17         driver = props.getProperty("driver");
18         url = props.getProperty("url");
19         user = props.getProperty("user");
20         pass = props.getProperty("pass");
21     }
22     
23     public void query(String sql) throws Exception{
24         //加载驱动
25         Class.forName(driver);
26         try(
27             //获取数据库连接
28             Connection conn = DriverManager.getConnection(url, user, pass);
29             //使用Connection来创建一个PreparedStatement对象
30             //传入控制结果集可滚动、可更新的参数
31             PreparedStatement pstmt = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
32             ResultSet rs = pstmt.executeQuery()
33         ){
34             rs.last();
35             int rowCount = rs.getRow();
36             for(int i = rowCount; i > 0; i--){
37                 rs.absolute(i);
38                 System.out.println(rs.getString(1) + "\t"
39                     + rs.getString(2) + "\t" + rs.getString(3));
40                     //修改记录指针所指记录、第2列的值
41                     rs.updateString(2, "学生名" + i);
42                     //提交修改
43                     rs.updateRow();
44             }
45         }
46     }
47     
48     public static void main(String[] args) throws Exception{
49         ResultSetTest rt = new ResultSetTest();
50         rt.initParam("mysql.ini");
51         rt.query("select * from student_table");
52     }
53 }

View Code

图片 39

图片 40

    student_table表中记录受倒序输出,且当程序运行结束晚,student_table表中有着记录的student_name列的值都于涂改。

    若一旦创造而更新的结果集,则动用查询语句询问的数额一般只能来自于一个数据表,而且查询结果集中之数据列必须包含主键列,否则会惹更新失败。

  处理Blob类型数据:

    Blob(Binary Long
Object):是次进制长对象,Blob列常用于存储大文件,典型的Blob内容是一模一样摆放图或一个声音文件,由于她的特殊性,必须使特殊的措施来存储

    使用Blob列可以把图纸、声音等公事之二进制数据保存在数据库被,并可以自数据库中平复指定文件。

    若用拿图片插入数据库,显然不可知一直通过常备的SQL语句来成功,因为起一个关键问题——Blob常量无法代表。所以用Blob数据插入数据库需要采用

     PreparedStatement,该对象来一个术:setBinaryStream(int
parameterIndex, InputStream
x),该法可以吧指定参数传入二进制输入流,从而得以兑现用Blob数据保存

     到数据库的效果。

    需要打ResultSet里落出Blob数据时,可以调用ResultSet的getBlob(int
columnIndex)方法,该措施将回到一个Blob对象,Blob对象提供了getBinaryStream()方法来取得该

     Blob数据的输入流,也堪行使Blob对象提供的getBytes()方法直接取出该Blob对象封装的二进制数据。

    为了拿图片放入数据库,使用如下SQL语句建立一个数据表:

图片 41

    img_data
mediumblob;创建一个mediumblob类型的数据列,用于保存图片数

    mediumblob类型可存储16M内容,blob类型可存储64KB内容。

下面程序可以实现图片“上污染”——实际上就是用图片保存到数据库,并当右手边的列表框中显示图片的名,当用户双击列表框中的图片名时,左边窗口用显示该图形——实质就是是根据选中的ID从数据库里搜寻图片,并以那个形出:

图片 42图片 43

  1 import java.sql.*;
  2 import javax.swing.*;
  3 import java.awt.*;
  4 import java.awt.event.*;
  5 import java.util.Properties;
  6 import java.util.ArrayList;
  7 import java.io.*;
  8 import javax.swing.filechooser.FileFilter;
  9 
 10 public class BlobTest
 11 {
 12     JFrame jf = new JFrame("图片管理程序");
 13     private static Connection conn;
 14     private static PreparedStatement insert;
 15     private static PreparedStatement query;
 16     private static PreparedStatement queryAll;
 17     // 定义一个DefaultListModel对象
 18     private DefaultListModel<ImageHolder> imageModel
 19         = new DefaultListModel<>();
 20     private JList<ImageHolder> imageList = new JList<>(imageModel);
 21     private JTextField filePath = new JTextField(26);
 22     private JButton browserBn = new JButton("...");
 23     private JButton uploadBn = new JButton("上传");
 24     private JLabel imageLabel = new JLabel();
 25     // 以当前路径创建文件选择器
 26     JFileChooser chooser = new JFileChooser(".");
 27     // 创建文件过滤器
 28     ExtensionFileFilter filter = new ExtensionFileFilter();
 29     static
 30     {
 31         try
 32         {
 33             Properties props = new Properties();
 34             props.load(new FileInputStream("mysql.ini"));
 35             String driver = props.getProperty("driver");
 36             String url = props.getProperty("url");
 37             String user = props.getProperty("user");
 38             String pass = props.getProperty("pass");
 39             Class.forName(driver);
 40             // 获取数据库连接
 41             conn = DriverManager.getConnection(url , user , pass);
 42             // 创建执行插入的PreparedStatement对象,
 43             // 该对象执行插入后可以返回自动生成的主键
 44             insert = conn.prepareStatement("insert into img_table"
 45                 + " values(null,?,?)" , Statement.RETURN_GENERATED_KEYS);
 46             // 创建两个PreparedStatement对象,用于查询指定图片,查询所有图片
 47             query = conn.prepareStatement("select img_data from img_table"
 48                 + " where img_id=?");
 49             queryAll = conn.prepareStatement("select img_id, "
 50                 + " img_name from img_table");
 51         }
 52         catch (Exception e)
 53         {
 54             e.printStackTrace();
 55         }
 56     }
 57     public void init()throws SQLException
 58     {
 59         // -------初始化文件选择器--------
 60         filter.addExtension("jpg");
 61         filter.addExtension("jpeg");
 62         filter.addExtension("gif");
 63         filter.addExtension("png");
 64         filter.setDescription("图片文件(*.jpg,*.jpeg,*.gif,*.png)");
 65         chooser.addChoosableFileFilter(filter);
 66         // 禁止“文件类型”下拉列表中显示“所有文件”选项。
 67         chooser.setAcceptAllFileFilterUsed(false);
 68         // ---------初始化程序界面---------
 69         fillListModel();
 70         filePath.setEditable(false);
 71         // 只能单选
 72         imageList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 73         JPanel jp = new JPanel();
 74         jp.add(filePath);
 75         jp.add(browserBn);
 76         browserBn.addActionListener(event -> {
 77             // 显示文件对话框
 78             int result = chooser.showDialog(jf , "浏览图片文件上传");
 79             // 如果用户选择了APPROVE(赞同)按钮,即打开,保存等效按钮
 80             if(result == JFileChooser.APPROVE_OPTION)
 81             {
 82                 filePath.setText(chooser.getSelectedFile().getPath());
 83             }
 84         });
 85         jp.add(uploadBn);
 86         uploadBn.addActionListener(avt -> {
 87             // 如果上传文件的文本框有内容
 88             if (filePath.getText().trim().length() > 0)
 89             {
 90                 // 将指定文件保存到数据库
 91                 upload(filePath.getText());
 92                 // 清空文本框内容
 93                 filePath.setText("");
 94             }
 95         });
 96         JPanel left = new JPanel();
 97         left.setLayout(new BorderLayout());
 98         left.add(new JScrollPane(imageLabel) , BorderLayout.CENTER);
 99         left.add(jp , BorderLayout.SOUTH);
100         jf.add(left);
101         imageList.setFixedCellWidth(160);
102         jf.add(new JScrollPane(imageList) , BorderLayout.EAST);
103         imageList.addMouseListener(new MouseAdapter()
104         {
105             public void mouseClicked(MouseEvent e)
106             {
107                 // 如果鼠标双击
108                 if (e.getClickCount() >= 2)
109                 {
110                     // 取出选中的List项
111                     ImageHolder cur = (ImageHolder)imageList.
112                     getSelectedValue();
113                     try
114                     {
115                         // 显示选中项对应的Image
116                         showImage(cur.getId());
117                     }
118                     catch (SQLException sqle)
119                     {
120                         sqle.printStackTrace();
121                     }
122                 }
123             }
124         });
125         jf.setSize(620, 400);
126         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
127         jf.setVisible(true);
128     }
129     // ----------查找img_table填充ListModel----------
130     public void fillListModel()throws SQLException
131     {
132 
133         try(
134             // 执行查询
135             ResultSet rs = queryAll.executeQuery())
136         {
137             // 先清除所有元素
138             imageModel.clear();
139             // 把查询的全部记录添加到ListModel中
140             while (rs.next())
141             {
142                 imageModel.addElement(new ImageHolder(rs.getInt(1)
143                     ,rs.getString(2)));
144             }
145         }
146     }
147     // ---------将指定图片放入数据库---------
148     public void upload(String fileName)
149     {
150         // 截取文件名
151         String imageName = fileName.substring(fileName.lastIndexOf('\\')
152             + 1 , fileName.lastIndexOf('.'));
153         File f = new File(fileName);
154         try(
155             InputStream is = new FileInputStream(f))
156         {
157             // 设置图片名参数
158             insert.setString(1, imageName);
159             // 设置二进制流参数
160             insert.setBinaryStream(2, is , (int)f.length());
161             int affect = insert.executeUpdate();
162             if (affect == 1)
163             {
164                 // 重新更新ListModel,将会让JList显示最新的图片列表
165                 fillListModel();
166             }
167         }
168         catch (Exception e)
169         {
170             e.printStackTrace();
171         }
172     }
173     // ---------根据图片ID来显示图片----------
174     public void showImage(int id)throws SQLException
175     {
176         // 设置参数
177         query.setInt(1, id);
178         try(
179             // 执行查询
180             ResultSet rs = query.executeQuery())
181         {
182             if (rs.next())
183             {
184                 // 取出Blob列
185                 Blob imgBlob = rs.getBlob(1);
186                 // 取出Blob列里的数据
187                 ImageIcon icon=new ImageIcon(imgBlob.getBytes(1L
188                     ,(int)imgBlob.length()));
189                 imageLabel.setIcon(icon);
190             }
191         }
192     }
193     public static void main(String[] args)throws SQLException
194     {
195         new BlobTest().init();
196     }
197 }
198 // 创建FileFilter的子类,用以实现文件过滤功能
199 class ExtensionFileFilter extends FileFilter
200 {
201     private String description = "";
202     private ArrayList<String> extensions = new ArrayList<>();
203     // 自定义方法,用于添加文件扩展名
204     public void addExtension(String extension)
205     {
206         if (!extension.startsWith("."))
207         {
208             extension = "." + extension;
209             extensions.add(extension.toLowerCase());
210         }
211     }
212     // 用于设置该文件过滤器的描述文本
213     public void setDescription(String aDescription)
214     {
215         description = aDescription;
216     }
217     // 继承FileFilter类必须实现的抽象方法,返回该文件过滤器的描述文本
218     public String getDescription()
219     {
220         return description;
221     }
222     // 继承FileFilter类必须实现的抽象方法,判断该文件过滤器是否接受该文件
223     public boolean accept(File f)
224     {
225         // 如果该文件是路径,接受该文件
226         if (f.isDirectory()) return true;
227         // 将文件名转为小写(全部转为小写后比较,用于忽略文件名大小写)
228         String name = f.getName().toLowerCase();
229         // 遍历所有可接受的扩展名,如果扩展名相同,该文件就可接受。
230         for (String extension : extensions)
231         {
232             if (name.endsWith(extension))
233             {
234                 return true;
235             }
236         }
237         return false;
238     }
239 }
240 // 创建一个ImageHolder类,用于封装图片名、图片ID
241 class ImageHolder
242 {
243     // 封装图片的ID
244     private int id;
245     // 封装图片的图片名字
246     private String name;
247     public ImageHolder(){}
248     public ImageHolder(int id , String name)
249     {
250         this.id = id;
251         this.name = name;
252     }
253     // id的setter和getter方法
254     public void setId(int id)
255     {
256         this.id = id;
257     }
258     public int getId()
259     {
260         return this.id;
261     }
262     // name的setter和getter方法
263     public void setName(String name)
264     {
265         this.name = name;
266     }
267     public String getName()
268     {
269         return this.name;
270     }
271     // 重写toString方法,返回图片名
272     public String toString()
273     {
274         return name;
275     }
276 }

View Code

图片 44

  使用ResultSetMetaData分析结果集:

    当执行SQL查询后得以经过运动记录指针来任何历ResultSet的各级条记下,但顺序可能不知道该ResultSet里富含哪些数据列,以及每个数据列的数据类型,那么可以接

     过ResultSetMetaData来得到有关ResultSet的讲述信息:

    MetaData的意思是首家数据,即描述其他数据的数,因此ResultSetMetaData封装了叙ResultSet对象的数目;后面还要介绍的DatabaseMetaData则封装了叙

     Database的数据。

    ResultSet中包含了一个getMetaData()方法,该办法好回来该ResultSet对应之ResultSetMetaData对象。一旦取得了ResultSetMetaData对象就是得透过

     ResultSetMetaData提供的大方艺术来回到ResultSet的描述信息。常因此智发生如下三单:

      1.int getColumnCount():返回该ResultSet的排列数量

      2.String getColumnName(int Column):返回指定索引的列名

      3.int getColumnType(int column):返回指定索引的列类型

下是一个大概的查询器,当用户在文本框内输入合法的查询语句并实行成功后,下面表格将会显得查询结果:

图片 45图片 46

  1 import java.awt.*;
  2 import java.awt.event.*;
  3 import javax.swing.*;
  4 import javax.swing.table.*;
  5 import java.util.*;
  6 import java.io.*;
  7 import java.sql.*;
  8 
  9 public class QueryExecutor
 10 {
 11     JFrame jf = new JFrame("查询执行器");
 12     private JScrollPane scrollPane;
 13     private JButton execBn = new JButton("查询");
 14     // 用于输入查询语句的文本框
 15     private JTextField sqlField = new JTextField(45);
 16     private static Connection conn;
 17     private static Statement stmt;
 18     // 采用静态初始化块来初始化Connection、Statement对象
 19     static
 20     {
 21         try
 22         {
 23             Properties props = new Properties();
 24             props.load(new FileInputStream("mysql.ini"));
 25             String drivers = props.getProperty("driver");
 26             String url = props.getProperty("url");
 27             String username = props.getProperty("user");
 28             String password = props.getProperty("pass");
 29             // 加载数据库驱动
 30             Class.forName(drivers);
 31             // 取得数据库连接
 32             conn = DriverManager.getConnection(url, username, password);
 33             stmt = conn.createStatement();
 34         }
 35         catch (Exception e)
 36         {
 37             e.printStackTrace();
 38         }
 39     }
 40     // --------初始化界面的方法---------
 41     public void init()
 42     {
 43         JPanel top = new JPanel();
 44         top.add(new JLabel("输入查询语句:"));
 45         top.add(sqlField);
 46         top.add(execBn);
 47         // 为执行按钮、单行文本框添加事件监听器
 48         execBn.addActionListener(new ExceListener());
 49         sqlField.addActionListener(new ExceListener());
 50         jf.add(top , BorderLayout.NORTH);
 51         jf.setSize(680, 480);
 52         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 53         jf.setVisible(true);
 54     }
 55     // 定义监听器
 56     class ExceListener implements ActionListener
 57     {
 58         public void actionPerformed(ActionEvent evt)
 59         {
 60             // 删除原来的JTable(JTable使用scrollPane来包装)
 61             if (scrollPane != null)
 62             {
 63                 jf.remove(scrollPane);
 64             }
 65             try(
 66                 // 根据用户输入的SQL执行查询
 67                 ResultSet rs = stmt.executeQuery(sqlField.getText()))
 68             {
 69                 // 取出ResultSet的MetaData
 70                 ResultSetMetaData rsmd = rs.getMetaData();
 71                 Vector<String> columnNames =  new Vector<>();
 72                 Vector<Vector<String>> data = new Vector<>();
 73                 // 把ResultSet的所有列名添加到Vector里
 74                 for (int i = 0 ; i < rsmd.getColumnCount(); i++ )
 75                 {
 76                     columnNames.add(rsmd.getColumnName(i + 1));
 77                 }
 78                 // 把ResultSet的所有记录添加到Vector里
 79                 while (rs.next())
 80                 {
 81                     Vector<String> v = new Vector<>();
 82                     for (int i = 0 ; i < rsmd.getColumnCount(); i++ )
 83                     {
 84                         v.add(rs.getString(i + 1));
 85                     }
 86                     data.add(v);
 87                 }
 88                 // 创建新的JTable
 89                 JTable table = new JTable(data , columnNames);
 90                 scrollPane = new JScrollPane(table);
 91                 // 添加新的Table
 92                 jf.add(scrollPane);
 93                 // 更新主窗口
 94                 jf.validate();
 95             }
 96             catch (Exception e)
 97             {
 98                 e.printStackTrace();
 99             }
100         }
101     }
102     public static void main(String[] args)
103     {
104         new QueryExecutor().init();
105     }
106 }

View Code

图片 47

    虽然ResultSetMetaData可以精确之辨析出ResultSet里富含多少排列,以及每列的列名、数据类型等,但下ResultSetMetaData需要自然之网开发,因此一旦在编程过程遭到

     已经清楚ResultSet里含多少排列,以及每列的列名、类型等消息,就没有必要采取ResultSetMetaData来分析该ResultSet对象了。

  Java7的RowSet1.1:

    RowSet接口连续了ResultSet接口,RowSet接口下富含JdbcRowSet、CachedRowSet、FilteredRowSet、JoinRowSet和WebRowSet常用子接口。除了JdbcRowSet需要保证

     持与数据库连接之外,其余4单子接口都是离线的RowSet,无需保持与数据库的连续。

    与ResultSet相比,RowSet默认是只是滚动、可更新、可序列化的结果集,而且作为JavaBean使用,因此会有利于地以网络达到传,用于共同两端的数。对于离线RowSet而

     言,程序于创立RowSet时曾将多少从脚数据库读取到内存,因此得以充分利用计算机内存,从而降低数据库服务器的载荷,提高程序性能。

  Java7新增的RowSetFactory与RowSet:

    Java7新长了RowSetProvider类和RowSetFactory接口,其中RowSetProvider负责创建RowSetFactory,而RowSetFactory则提供了之类方法来创造RowSet实例:

      1.CachedRowSet
createCachedRowSet():创建一个默认的CachedRowSet。

      2.FilteredRowSet
createFilteredRowSet():创建一个默认的FilteredRowSet。

      3.JdbcRowSet createJdbcRowSet():创建一个默认的JdbcRowSet。

      4.JoinRowSet createJoinRowSet():创建一个默认的JoinRowSet。

      5.WebRowSet createWebRowSet():创建一个默认的WebRowSet。

    通过动用RowSetFactory,就可以拿应用程序与RowSet实现类分离开,有利于后期的升级、扩展。

下面用RowSetFactory来创造JdbcRowSet实例:

图片 48图片 49

 1 import java.util.*;
 2 import java.io.*;
 3 import java.sql.*;
 4 import javax.sql.rowset.*;
 5 
 6 public class RowSetFactoryTest
 7 {
 8     private String driver;
 9     private String url;
10     private String user;
11     private String pass;
12     public void initParam(String paramFile)throws Exception
13     {
14         // 使用Properties类来加载属性文件
15         Properties props = new Properties();
16         props.load(new FileInputStream(paramFile));
17         driver = props.getProperty("driver");
18         url = props.getProperty("url");
19         user = props.getProperty("user");
20         pass = props.getProperty("pass");
21     }
22 
23     public void update(String sql)throws Exception
24     {
25         // 加载驱动
26         Class.forName(driver);
27         // 使用RowSetProvider创建RowSetFactory
28         RowSetFactory factory = RowSetProvider.newFactory();
29         try(
30             // 使用RowSetFactory创建默认的JdbcRowSet实例
31             JdbcRowSet jdbcRs = factory.createJdbcRowSet())
32         {
33             // 设置必要的连接信息
34             jdbcRs.setUrl(url);
35             jdbcRs.setUsername(user);
36             jdbcRs.setPassword(pass);
37             // 设置SQL查询语句
38             jdbcRs.setCommand(sql);
39             // 执行查询
40             jdbcRs.execute();
41             jdbcRs.afterLast();
42             // 向前滚动结果集
43             while (jdbcRs.previous())
44             {
45                 System.out.println(jdbcRs.getString(1)
46                     + "\t" + jdbcRs.getString(2)
47                     + "\t" + jdbcRs.getString(3));
48                 if (jdbcRs.getInt("student_id") == 3)
49                 {
50                     // 修改指定记录行
51                     jdbcRs.updateString("student_name", "孙悟空");
52                     jdbcRs.updateRow();
53                 }
54             }
55         }
56     }
57     public static void main(String[] args)throws Exception
58     {
59         RowSetFactoryTest jt = new RowSetFactoryTest();
60         jt.initParam("mysql.ini");
61         jt.update("select * from student_table");
62     }
63 }

View Code

图片 50

上面程序行使RowSetFactory来创造JdbcRowSet对象。由于经过这种办法创造的JdbcRowSet还未曾传到Connection参数,因此次还亟需调用setUrl()、setUsername()、setPassword()等方式来安装数据库连接信息。

  离线RowSet:

    在使用ResultSet的秋,程序查询得到ResultSet之后必须及时读取或拍卖它对应之笔录,否则要关闭Connection,再经ResultSet读博记录就是见面引发那个。

    离线RowSet会一直用脚数据读入内存中,封装成RowSet对象,而RowSet对象则完全好当成JavaBean来运,因此不但安全,且编程十分简练。CachedRowSet是

     所有离线RowSet的父接口。

下面为CachedRowSet为例进行介绍:

图片 51图片 52

 1 import java.util.*;
 2 import java.io.*;
 3 import java.sql.*;
 4 import javax.sql.*;
 5 import javax.sql.rowset.*;
 6 
 7 public class CachedRowSetTest
 8 {
 9     private static String driver;
10     private static String url;
11     private static String user;
12     private static String pass;
13     public void initParam(String paramFile)throws Exception
14     {
15         // 使用Properties类来加载属性文件
16         Properties props = new Properties();
17         props.load(new FileInputStream(paramFile));
18         driver = props.getProperty("driver");
19         url = props.getProperty("url");
20         user = props.getProperty("user");
21         pass = props.getProperty("pass");
22     }
23 
24     public CachedRowSet query(String sql)throws Exception
25     {
26         // 加载驱动
27         Class.forName(driver);
28         // 获取数据库连接
29         Connection conn = DriverManager.getConnection(url , user , pass);
30         Statement stmt = conn.createStatement();
31         ResultSet rs = stmt.executeQuery(sql);
32         // 使用RowSetProvider创建RowSetFactory
33         RowSetFactory factory = RowSetProvider.newFactory();
34         // 创建默认的CachedRowSet实例
35         CachedRowSet cachedRs = factory.createCachedRowSet();
36         // 使用ResultSet装填RowSet
37         cachedRs.populate(rs);    // ①
38         // 关闭资源
39         rs.close();
40         stmt.close();
41         conn.close();
42         return cachedRs;
43     }
44     public static void main(String[] args)throws Exception
45     {
46         CachedRowSetTest ct = new CachedRowSetTest();
47         ct.initParam("mysql.ini");
48         CachedRowSet rs = ct.query("select * from student_table");
49         rs.afterLast();
50         // 向前滚动结果集
51         while (rs.previous())
52         {
53             System.out.println(rs.getString(1)
54                 + "\t" + rs.getString(2)
55                 + "\t" + rs.getString(3));
56             if (rs.getInt("student_id") == 3)
57             {
58                 // 修改指定记录行
59                 rs.updateString("student_name", "孙悟空");
60                 rs.updateRow();
61             }
62         }
63         // 重新获取数据库连接
64         Connection conn = DriverManager.getConnection(url
65             , user , pass);
66         conn.setAutoCommit(false);
67         // 把对RowSet所做的修改同步到底层数据库
68         rs.acceptChanges(conn);
69     }
70 }

View Code

图片 53

  从地方程序可以望在Connection关闭的场面下,程序依然可以读取、修改RowSet里的记录。为了以顺序对离线RowSet所召开的改共到脚数据库,程序在调用RowSet的

   acceptChanges()方法时,必须传入Connection。

  离线RowSet的询问分页:

    由于CachedRowSet会将数据记录第一手装到内存中,若SQL查询返回的笔录了那个,CachedRowSet将会见占据大量内存,在好几最情况下,将会晤导致内存溢出。

    未缓解上述问题,CachedRowSet提供了分页功能。即一律次仅装载ResultSet里之某某几乎久记下,这样尽管避免了CachedRowSet占用内存过特别之题目。

    CachedRowSet提供了之类方法控制分页:

      1.populate(ResultSet rs, int
startRow):使用给定的ResultSet装填RowSet,从ResultSet的第startRow条记录开始堵

      2.setPageSize(int
pageSize):设置CachedRowSet每次回多少条记下

      3.previousPage():在脚ResultSet可用的事态下,让CachedRowSet读博上同页记录。

      4.nextPage():在底部ResultSet可用的景况下,让CachedRowSet读博下一致页记录

下程序示范了CachedRowSet的分页支持:

图片 54图片 55

 1 import java.util.*;
 2 import java.io.*;
 3 import java.sql.*;
 4 import javax.sql.*;
 5 import javax.sql.rowset.*;
 6 
 7 public class CachedRowSetPage
 8 {
 9     private String driver;
10     private String url;
11     private String user;
12     private String pass;
13     public void initParam(String paramFile)throws Exception
14     {
15         // 使用Properties类来加载属性文件
16         Properties props = new Properties();
17         props.load(new FileInputStream(paramFile));
18         driver = props.getProperty("driver");
19         url = props.getProperty("url");
20         user = props.getProperty("user");
21         pass = props.getProperty("pass");
22     }
23 
24     public CachedRowSet query(String sql , int pageSize
25         , int page)throws Exception
26     {
27         // 加载驱动
28         Class.forName(driver);
29         try(
30             // 获取数据库连接
31             Connection conn = DriverManager.getConnection(url , user , pass);
32             Statement stmt = conn.createStatement();
33             ResultSet rs = stmt.executeQuery(sql))
34         {
35             // 使用RowSetProvider创建RowSetFactory
36             RowSetFactory factory = RowSetProvider.newFactory();
37             // 创建默认的CachedRowSet实例
38             CachedRowSet cachedRs = factory.createCachedRowSet();
39             // 设置每页显示pageSize条记录
40             cachedRs.setPageSize(pageSize);
41             // 使用ResultSet装填RowSet,设置从第几条记录开始
42             cachedRs.populate(rs , (page - 1) * pageSize + 1);
43             return cachedRs;
44         }
45     }
46     public static void main(String[] args)throws Exception
47     {
48         CachedRowSetPage cp = new CachedRowSetPage();
49         cp.initParam("mysql.ini");
50         CachedRowSet rs = cp.query("select * from student_table" , 3 , 2);   // ①
51         // 向后滚动结果集
52         while (rs.next())
53         {
54             System.out.println(rs.getString(1)
55                 + "\t" + rs.getString(2)
56                 + "\t" + rs.getString(3));
57         }
58     }
59 }

View Code

图片 56

次中要查询第2页的笔录,每页显示3长达记下。

事务处理:

  事物之概念以及MySQL事务支持:

    事务是由同样步还是几乎步数据库操作序列组成的逻辑执行单元,这一系列操作还是全部履,要么全部放弃实行。

    事务有四只性状:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和连绵(Durability)。简称ACID特性。

  JDBC的工作支持:

    JDBC连接的事务支持有Connection提供,Connection默认打开自动提交,即关闭工作。这种情况下,每一样久SQL语句一旦实施,便会这付给到数据库,永久生效,无法

     对该进行回滚操作。

    可调用Connection的setAutoCommit()方法来关闭自动提交,开启事务:

    //conn.setAutoCommit(false);

    等及独具SQL语句都于实践,程序可以调用Connection的commit()方法来交付业务:

    //conn.commit();

    若任意一长条SQL语句执行破产,则当据此Connection的rollback()方法来回滚事务:

    //conn.rollback();

    实际上,当Connection遇到一个非处理的SQLException异常时,系统将会晤怪退出,事务也会见活动回滚。但要是序捕获了拖欠老,则需以十分处理块被显式地回滚

     事务

图片 57图片 58

 1 import java.sql.*;
 2 import java.io.*;
 3 import java.util.*;
 4 
 5 public class TransactionTest
 6 {
 7     private String driver;
 8     private String url;
 9     private String user;
10     private String pass;
11     public void initParam(String paramFile)throws Exception
12     {
13         // 使用Properties类来加载属性文件
14         Properties props = new Properties();
15         props.load(new FileInputStream(paramFile));
16         driver = props.getProperty("driver");
17         url = props.getProperty("url");
18         user = props.getProperty("user");
19         pass = props.getProperty("pass");
20     }
21     public void insertInTransaction(String[] sqls) throws Exception
22     {
23         // 加载驱动
24         Class.forName(driver);
25         try(
26             Connection conn = DriverManager.getConnection(url , user , pass))
27         {
28             // 关闭自动提交,开启事务
29             conn.setAutoCommit(false);
30             try(
31                 // 使用Connection来创建一个Statment对象
32                 Statement stmt = conn.createStatement())
33             {
34                 // 循环多次执行SQL语句
35                 for (String sql : sqls)
36                 {
37                     stmt.executeUpdate(sql);
38                 }
39             }
40             // 提交事务
41             conn.commit();
42         }
43     }
44     public static void main(String[] args) throws Exception
45     {
46         TransactionTest tt = new TransactionTest();
47         tt.initParam("mysql.ini");
48         String[] sqls = new String[]{
49             "insert into student_table values(null , 'aaa' ,1)",
50             "insert into student_table values(null , 'bbb' ,1)",
51             "insert into student_table values(null , 'ccc' ,1)",
52             // 下面这条SQL语句将会违反外键约束,
53             // 因为teacher_table中没有ID为5的记录。
54             "insert into student_table values(null , 'ccc' ,5)" //①
55         };
56         tt.insertInTransaction(sqls);
57     }
58 }

View Code

图片 59

 上面代码报错会因为插入入语句第四条发出摩擦。正是为当时长达告句出错,导致发生大,且该特别没有到手处理,引起程序非正常结束,所以工作自动回滚,上面3长条插入语句无效。

    Connection也提供了设置中间点的方式:

      1.Savepoint
setSavepoint():在眼前作业中创造一个勿命名的中间点,并回代表该中间点的Savepoint对象

      2.Savepoint setSavepoint(String
name):在时下政工中开创一个装有指定名称的中间点,并回代表该中间点的SavepointSavepoint对象。

    通常来说设置中间点时,没有必要指定名称,因为Connection回滚到指定中间点时,并无是基于名字回滚的,而是基于中间点对象回滚的,Connection提供了

     rollback(Savepoint savepoint)方法回滚到指定中间点。

  Java8加强的批量翻新:

    JDBC还提供了一个批量更新的效用,批量翻新时,多条SQL语句以吃当做同一批操作为以收集,并同时提交。

    批量更新得获得底层数据库的支撑,可以通过调用DatabaseMetaData的supportsBatchUpdates()方法来查底层数据库是否支持批量更新。

    使用批量创新得事先创造一个Statement对象,然后使用该对象的addBatch()方法将大半长长的SQL语句以采集,最后调用Java8个Statement对象新增的executeLargeBatch()或

     原有的executeBatch()方法而实行这些SQL语句。只要批量操作着另外一样条SQL语句影响的记录条数可能过Integer.MAX_VALUE,就应当使用executeLargeBatch()方

     法。如下:

图片 60图片 61

1 Statement stmt = conn.createStatement();
2 //使用Statement同时收集多条SQL语句
3 stmt.addBatch(sql1);
4 stmt.addBatch(sql2);
5 stmt.addBatch(sql3);
6 ...
7 //同时执行所有的SQL语句
8 stmt.executeLargeBatch();

View Code

    若在批量更新的addBatch()方法被上加了select查询语句,程序用会直接出现谬误。为了给批量操作可以对的处理错误,必须将批量履之操作视为单个事务,若批量还

     新在实施过程遭到破产,则于事情回滚到批量操作起来之前的状态。为直达这种意义,程序应该以开批量操作前先关自动提交,然后起收集更新语句,当批量操作

     执行了晚,提交业务,并恢复之前的活动提交模式,如下:

图片 62图片 63

 1 //保存当前的自动的提交模式
 2 boolean autoCommit = conn.getAutoCommit();
 3 //关闭自动提交
 4 conn.setAutoCommit(false);
 5 Statement stmt = conn.createStatement();
 6 //使用Statement同时收集多条SQL语句
 7 stmt.addBatch(sql1);
 8 stmt.addBatch(sql2);
 9 stmt.addBatch(sql3);
10 ...
11 //同时执行所有的SQL语句
12 stmt.executeLargeBatch();
13 //提交修改
14 conn.commit();
15 //恢复原有的紫东提交模式
16 conn.setAutocommit(autoCommit);

View Code

    MySQL的风靡驱动依然未支持executeLargeBatch()方法,对于数据库让不支持executeLargeBatch()的状态,则不得不依然采用传统的executeBatch()方法。

浅析数据库信息:

  使用DatabaseMetaData分析数据库信息:

    JDBC提供了DatabaseMetaData来封装数据库连接对应数据库的消息,通过Connection提供的getMetaData()方法就可以获取数据库对应的DatabaseMetaData对象

    DatabaseMetaData接口通常由驱动程序供应商提供实现,其目的是于用户了解底层数据库的连带信息。使用该接口的目的是发现什么处理底层数据库,尤其是对此打算和

     多独数据库一起行使的应用程序——因为应用程序需要以差不多个数据库里切换,所以必须采用该接口来找来脚数据库的意义,如:调用supportsCorrelatedSubqueries

     ()方法查看是否可以以关联子查询,或者调用supportsBatchUpdates()方法查看是否足以下批量翻新。

    许多DatabaseMetaData方法为ResultSet对象的形式返回查询信息,然后使ResultSet的正规方式(如:getString()和getInt())即可从这些ResultSet对象被获取数据。若

     查询的音信不可用,则拿回来一个空ResultSet对象。

    DatabaseMetaData的森措施都用传入一个XXXPattern模式字符串,这里的XXXPattern不是正则表达式,而是SQL里之模式字符串,即用%象征擅自多单字符,使用下

     划线代表一个字符。在通常状态下,若将欠模式字符串的参数值设置也null,即表明该参数不当作过滤条件。

    下面程序通过DatabaseMetaData分析了即Connection连接对应数据库的有的基本信息,包括目前数据库含多少数据表,存储过程,student_table表的数据列、主键、

     外键等消息:

图片 64图片 65

 1 import java.sql.*;
 2 import java.util.*;
 3 import java.io.*;
 4 
 5 public class DatabaseMetaDataTest
 6 {
 7     private String driver;
 8     private String url;
 9     private String user;
10     private String pass;
11     public void initParam(String paramFile)throws Exception
12     {
13         // 使用Properties类来加载属性文件
14         Properties props = new Properties();
15         props.load(new FileInputStream(paramFile));
16         driver = props.getProperty("driver");
17         url = props.getProperty("url");
18         user = props.getProperty("user");
19         pass = props.getProperty("pass");
20     }
21     public void info() throws Exception
22     {
23         // 加载驱动
24         Class.forName(driver);
25         try(
26             // 获取数据库连接
27             Connection conn = DriverManager.getConnection(url
28                 , user , pass))
29         {
30             // 获取的DatabaseMetaData对象
31             DatabaseMetaData dbmd = conn.getMetaData();
32             // 获取MySQL支持的所有表类型
33             ResultSet rs = dbmd.getTableTypes();
34             System.out.println("--MySQL支持的表类型信息--");
35             printResultSet(rs);
36             // 获取当前数据库的全部数据表
37             rs = dbmd.getTables(null,null, "%" , new String[]{"TABLE"});
38             System.out.println("--当前数据库里的数据表信息--");
39             printResultSet(rs);
40             // 获取student_table表的主键
41             rs = dbmd.getPrimaryKeys(null , null, "student_table");
42             System.out.println("--student_table表的主键信息--");
43             printResultSet(rs);
44             // 获取当前数据库的全部存储过程
45             rs = dbmd.getProcedures(null , null, "%");
46             System.out.println("--当前数据库里的存储过程信息--");
47             printResultSet(rs);
48             // 获取teacher_table表和student_table之间的外键约束
49             rs = dbmd.getCrossReference(null,null, "teacher_table"
50                 , null, null, "student_table");
51             System.out.println("--teacher_table表和student_table之间"
52                 + "的外键约束--");
53             printResultSet(rs);
54             // 获取student_table表的全部数据列
55             rs = dbmd.getColumns(null, null, "student_table", "%");
56             System.out.println("--student_table表的全部数据列--");
57             printResultSet(rs);
58         }
59     }
60     public void printResultSet(ResultSet rs)throws SQLException
61     {
62         ResultSetMetaData rsmd = rs.getMetaData();
63         // 打印ResultSet的所有列标题
64         for (int i = 0 ; i < rsmd.getColumnCount() ; i++ )
65         {
66             System.out.print(rsmd.getColumnName(i + 1) + "\t");
67         }
68         System.out.print("\n");
69         // 打印ResultSet里的全部数据
70         while (rs.next())
71         {
72             for (int i = 0; i < rsmd.getColumnCount() ; i++ )
73             {
74                 System.out.print(rs.getString(i + 1) + "\t");
75             }
76             System.out.print("\n");
77         }
78         rs.close();
79     }
80     public static void main(String[] args)
81         throws Exception
82     {
83         DatabaseMetaDataTest dt = new DatabaseMetaDataTest();
84         dt.initParam("mysql.ini");
85         dt.info();
86     }
87 }

View Code

图片 66

结果绝多,只截取一片段。

  使用系统表分析数据库信息:

    除了DatabaseMetaData来分析底层数据库信息之外,若曾规定应用程序所以用之数据库系统,则可经过数据库的系统来分析数据库信息。

    系统表又叫做数据字典,数据字典的数量一般由数据库系统承担保护,用户日常只能查询数据字典,而未可知改改数据字典的始末。

    MySQL数据库使用information_schema数据库来保存系统表,在数据库里噙了大量系统表,常用系统表的简要介绍如下:

      1.tables:存放数据库里所有数据表信息

      2.schemata:存放数据库里所有数据库的信息

      3.views:存放数据库里所有视图的音

      4.columns:存放数据库里所有列的音信

      5.triggers:存放数据库里所有触发器的消息

      6.routines:存放数据库里所有存储过程和函数的信

      7.key_column_usage:存放数据库里所有具有约束之键信息

      8.table_constraints:存放数据库里全部约束表的音讯

      9.statistics:存放数据库里全部索引的消息

动连接池管理总是:

  数据库连接的建立和倒闭是最耗费系统资源的操作,数据库连接池的化解方案是:当应用程序启动时,系统积极建立足够的数据库连接,并拿这些连成一个连接池。每次应

   用程序要数据库连接是,无需更打开连接,而是从连续池中取出就部分连续使用,使用完后不再关闭数据库连接,而是径直拿连归还给连接池。

  对于共享资源的状况,有一个通用的设计模式:资源池(Resource
Pool),用于缓解资源的屡屡请、释放所招的性能降低。

  数据库连接池是Connection对象的工厂,数据库连接池的常用参数如下:

    1.数据库的起连接数

    2.连接池的绝大连接数

    3.连接池的极其小连接数

    4.连接池每次多的容量

  JDBC的数据库连接池使用
javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由商用服务器提供实现,也生一对开源组织提供实现(如DBCP和C3P0)。

  DBCP数据源:

    DBCP是Apache软件基金组织下的开源连接实现,该连接池依赖该团伙下的别样一个开源系统:common-pool。若需要运用该连接池实现,则承诺在系统受到增有限单jar
文件:

      1.commons-dbcp.jar:连接池的贯彻

      2.commons-pool.jar:连接池落实之依赖库

    Tomcat的连接池正是以该连接池实现的。数据库连接池既可以与应用服务器整合应用,也得以由应用程序独立行使。

    下面代码有示范了下DBCP来收获数据库连接方式:

图片 67图片 68

 1 //创建连接池实例
 2 BasicDataSource ds = new BasicDataSourc();
 3 //设置连接池所需驱动
 4 ds.setDriverClassName("com.mysql.jdbc.Driver");
 5 //设置连接数据库的URL
 6 ds.setUrl("jdbc:mysql://localhost:3306/javaee");
 7 //设置连接数据库的用户名
 8 ds.setUsername("root");
 9 //设置连接数据库的密码
10 ds.setPassword("pass");
11 //设置连接池的初始连接数
12 ds.setInitialSize(5);
13 //设置连接池最多可有多少个活动连接数
14 ds.setMaxActive(20);
15 //设置连接池中最少有2个空闲的连接
16 ds.setMinIdle(2);

View Code

    数据源和数据库连接不同,数据源无需创建多独,它是有数据库连接的工厂,因此所有应用只需要一个数据源即可。即:一个用,上面代码只待实施同样不行即可。

    建议将地方程序中的ds设置成static成员变量,并且以使用起来时立即初始化数据源对象,程序中有需要获取数据库连接的地方一直看该ds对象,并获取数据库连接即

     可。

    //通过数据源获取数据库连接

    Connection conn = ds.getConnection();

    当数据库访问结束后,程序还是如以前一样关闭数据库连接:

    //释放数据库连接

    conn.close();

  C3P0数据源:

    C3P0数据源性能更胜一筹,Hibernate就推荐使用该连接池。C3P0连接池不仅可自行清理无以使用的Connection,还得自动清理ResultSet和Statement。

    若得采用C3P0连接池,则答应在系统中追加如下JAR文件

      1.c3p0-0.9.1.2.jar:C3P0连接池的兑现

    下面代码通过C3P0连接池获得数据库连接:

图片 69图片 70

 1 //创建连接池实例
 2 ComboPooledDataSource ds = new ComboPooledDataSource();
 3 //设置连接池所需驱动
 4 ds.setDriverClass("com.mysql.jdbc.Driver");
 5 //设置连接数据库的URL
 6 ds.setJdbcUrl("jdbc:mysql://localhost:3306/javaee");
 7 //设置连接数据库的用户名
 8 ds.setUser("root");
 9 //设置连接数据库的密码
10 ds.setPassword("pass");
11 //设置连接池的最大连接数
12 ds.setMaxPoolSize(40);
13 //设置连接池的最小连接数
14 ds.setMinPoolSIze(2);
15 //设置连接池的初始连接数
16 ds.setInitialPoolSize(10);
17 //设置连接池的缓存Statement的最大数
18 ds.setMaxStatements(180);

View Code

    通过如下代码获取数据库连接:

    Connection conn = ds.getConnection();

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 mobile.365-838.com 版权所有