JDBC入门知识

一、JDBC入门


1、什么是JDBC?

      JDBC(Java  DataBase  Connectivity)就是Java数据库连接,说白了就是用Java语言操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是使用Java语言向数据库发送SQL语句。

2、JDBC的原理

      早期SUN公司的天才们想编写一套可以连接天下所有数据库的API,但是当他们开始时发现这是不可能完成的任务,因为各个厂商的数据库差异太大了。后来SUN公司开始于数据库厂商们讨论,最终得出的结论是,由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后个数据库厂商会遵循SUN的规范提供一套访问自己公司数据库服务的API。SUN公司提供的规范命名为JDBC,而各个厂商提供的遵循了JDBC规范的,可以访问自己数据库的API称之为驱动。

      

      JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接,每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。

      当然还有第三方公司专门为某一数据库提供驱动,这样的驱动往往不是开元免费的。

3、JDBC核心类(接口)介绍

      JDBC的核心类有DriverManager、Connection、Statement和ResultSet。

      DriverManager(驱动管理器)的作用有两个:

  • 注册驱动:这可以让JDBC知道要使用的是哪个驱动。
  • 获取Connection:如果可以获取到Connection,那么说明已经与数据库连接上了。

      Connection对象表示链接,与数据库的通讯都通过这个对象展开:

  • Connection对象最重要的一个方法就是获取Statement对象。

      Statement是用来向数据库发送SQL语句的,这样数据库就会执行发送过来的SQL语句:

  • void  executeUpdate(String  sql):执行更新操作(insert,update,delete等)。
  • ResultSet  executeQuery(String  sql):执行查询操作,数据库在执行查询后会返回查询结果,查询结果就是ResultSet。

      ResultSet对象表示查询结果集,只有在执行查询操作后才会有结果集产生,结果集是一个二维表格。操作结果集要学习移动ResultSet内部的"行光标",以及获取当前行上每一列的数据:

  • boolean  next():使"行光标"移动到下一行,并返回移动后的行是否存在。
  • xxx  getXxx(int  col):获取当前行指定列上的值,参数就是列数,列数从1开始,而不是0。

4、编写一个JDBC程序

      下面开始编写第一个JDBC程序:

   【1】、mysql数据库驱动jar包:mysql-connector-java-5.1.13-bin.jar

   【2】、获取连接

        获取连接需要两步,一是使用DriverManager注册驱动,二是使用DriverManager获取connection对象。

  • 注册驱动

             看清楚了!注册驱动只有一句话:Class.forName(" com.mysql.jdbc.Driver "),下面的内容都是对这句代码的解释。

             DriverManager类的registerDriver()方法的参数是java.sql.Driver,但是java.sql.Driver是一个接口,实现类由mysql来提供,MySQL中java.sql.Driver接口的实现类为com.mysql.jdbc.Driver。

             注册驱动的代码如下:DriverManager.registerDriver(new  com.mysql.jdbc.Driver());

             上面的编码虽然可以注册驱动,是出现硬编码(代码以来MySQL驱动jar包),如果将来想要链接Oracle 数据库,那么必须要修改代码。并且其实这种注册驱动的方式是注册了两次驱动。

             JDBC中规定,驱动类被加载时,需要手动把自己注册到DriverManager中,下面我们来看看com.mysql.jdbc.Driver类的源码:

<span style="font-family:Arial;font-size:12px;">       public class Driver extends NonRegisteringDriver implements java.sql.Driver {
	    static {
		    try {
			   java.sql.DriverManager.registerDriver(new Driver());
		    } catch (SQLException E) {
			   throw new RuntimeException("Can't register driver!");
                    }
	     }
         ……
       }</span>

            com.mysql.jdbc.driver类中的static块会创建本类对象,并注册到DriverManager中。这说明主要去加载com.mysql.jdbc.Driver类,那么就会执行static块,从而也就把com.mysql.jdbc.driver注册到DriverManager中,所以把注册驱动类的代码改为加载驱动类。

            Class.forName("com.mysql.jdbc.Driver");

   【3】、获取链接的也只有一段代码:DriverManager.getConnection(url,username,password);其中username和password是登陆数据库的用户名和密码。

        url相对复杂一点,它是用来找到要连接的数据库地址,下面是mysql的url:jdbc:mysql://localhost:3306/mydb.

        JDBC规定url的格式有三部分组成,每个组成部分使用冒号分隔。

  • 第一部分是jdbc,这是固定的;
  • 第二部分是数据库名称,连接mysql数据库,第二部分就是mysql;
  • 第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由服务器IP(localhost)、端口号(3306)以及DATABASE名称组成。

        下面是获取连接的语句:

        Connection  con  =  DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb","root","123");

        还可以在URL中提供参数:

        jdbc:mysql://localhost:3306/mydb?useUnicode=true & characterEncoding=utf8

  • useUnicode参数,指定这个数据库链接过程中,使用的是Unicode字节集;
  • characterEncoding参数,指定连接数据库的过程中,使用的是UTF8字节集编码。

   【4】、获取Statement

        在得到Connection之后,说明已经与数据库连接上了,下面是通过Connection获取Statement对象的代码:Statement  stmt  =  con.createStatement();

        Statement是用来项数据库发送SQL语句的。

   【5】、发送SQL增、删、改语句

       String  sql  =  " INSERT  INTO  stu  VALUES(' zhangsan ',' 123 ') ";

        int  m  =  stmt.executeUpdate(sql);

       其中int类型的返回值,表示执行这条SQL语句所影响的行数,如果SQL语句执行失败,那么executeUpdate方法会抛出一个SQLException异常。

   【6】、发送SQL查询语句

        String  sql  =  " SELECT  * FROM  stu  ";

        ResultSet  rs  =  stmt.executeQuery(sql);

        请注意,执行查询使用的不是executeUpdate方法,而是executeQuery方法。executeQuery方法返回的是ResultSet,ResultSet封装了查询结果,称之为结果集。

   【7】、读取结果集中的数据

        ResultSet就是一张二维的表格,它内部有一个行光标,光标默认的位置在第一行的上方,我们可以调用rs对象的next()方法把" 行光标 "向下移动一行,当第一次调用next方法时," 行光标 "就到了第一行记录的位置,这样可以使用ResultSet提供的getXxx(int  col)方法获取指定类的数据了。

        rs.next();

        rs.getInt(1);

        如果不能确定数据的类型,可以使用getObject(int  col),或getString(int  col)等方法。

   【6】、关闭

        与IO流一样,使用后的东西都需要关闭,关闭的顺序是先得到的先关闭,后得到的后关闭。

        rs.close();

        stmt.close();

        con.close();

5、代码的规范化

   所谓规范化代码,就是无论是否出现异常,都要关闭ResultSet、Statement、以及Connection。

<span style="font-family:Arial;font-size:12px;">public void query{
      Connection con = null;
      Statement stmt = null;
      ResultSet rs = null;
      try{
            con = getConnection();
            stmt = con.createStatement();
            String sql = "SELECT * FROM user ";
            rs = stmt.executeQuery(sql);
            while(rs.next()){
                  String username = rs.getString(1);
                  String password = rs.getString(2);
            }catch(exception e){
                  throw new RuntimeException(e);
            }finally{
                  try{
                        if(rs!=null) rs.close();
                        if(stmt!=null) rs.close();
                        if(con!=null) rs.close();
                  }catch(SQLException e){}
            }
      }
}</span>

二、JDBC对象介绍


1、JDBC中的主要类(接口)

  • DriverManager
  • Connection
  • Statement
  • ResultSet

2、DriverManager

   其实我们今后只需要会用DriverManager的getConnection()方法即可。

        Class.forName(" com.mysql.jdbc.Driver ");

        String  url  =  " jdbc:mysql://localhost:3306/mydb ";

        String  username  =  " root ";

        String  password  =  " 123 ";

        Connection  con  =  DriverManager.getConnection(url,username,password);

   注意,上面代码可能出现的两个异常:

        ClassNotFoundException:这个异常是在第一句出现的,出现这个异常有两个可能,【1】没有给mysql的jar包,【2】类名写错了。

        SQLException:这个异常出现在第5句,查看三个参数是否有问题。

   对于DriverManager.registerDriver()方法了解即可,因为我们今后注册只会用到Class.forName(),而不会使用这个方法。

3、Connection

   Connection最为重要的方法就是获取Statement对象:

  • Statement stmt = con.createStatement();

   后面在学习ResultSet时,还要学习一下下面的方法:

  • Statement stmt = con.createStatement(int,int);

4、Statement

   Statement最为重要的方法就是:

  • int  executeUpdate(String  sql):执行更新操作,即执行insert、update、delete语句,其实这个方法也可以执行create table、alter table、drop table等语句,但我们很少使用JDBC来执行这些语句。
  • ResultSet  executeQuery(String  sql):执行查询操作,返回ResultSet,即结果集。

   Statement还有一个boolean  execute()方法,可以用来执行增、删、改、查所有SQL语句。该方法返回布尔型值,表示SQL语句是否有结果集。

   如果使用execute()方法执行的是更新语句,那么还要调用int getUpdateCount()来获取insert、update、delete语句所影响的行数。

   如果使用execute()方法执行的是查询语句,那么还要调用ResultSet getResultSet()来获取select语句的查询结果。

5、ResultSet之滚动结果集(了解)

   【1】ResultSet提供了一系列的方法来移动" 行光标 ":

  • void beforeFirst():把光标放到第一行的前面,这也是光标默认的位置;

  • void afterLast():把光标放到最后一行的后面;

  • boolean first():把光标放到第一行的位置上,返回值表示调控光标是否成功;

  • boolean last():把光标放到最后一行的位置上;

  • boolean isBeforeFirst():当前光标位置是否在第一行前面;

  • boolean isAfterLast():当前光标位置是否在最后一行的后面;

  • boolean isFirst():当前光标位置是否在第一行上;

  • boolean isLast():当前光标位置是否在最后一行上;

  • boolean previous():把光标向上挪一行;

  • boolean next():把光标向下挪一行;

  • boolean relative(int row):相对位移,当row为正数时,表示向下移动row行,为负数时表示向上移动row行;

  • boolean absolute(int row):绝对位移,把光标移动到指定的行上;

  • int getRow():返回当前光标所有行。

   上面的方法分为两类,一类用来判断游标位置的,另一类用来移动游标位置的。

   如果结果集是不可滚动的,那么只能使用next()方法来移动游标,而beforeFirst()、afterLast()、first()、last()、previous()、relative()方法都是不可用的!

   结果集是否支持滚动,要从Connection类的CreateStatement()方法说起,也就是说创建Statement决定了ResultSet是否支持滚动。

   createStatement(int  resultSetType,int  resultSetConcurrency):

      resultSetType参数的可选值:

  • ResultSet.TYPE_FORWARD_ONLY:不可滚动结果集;
  • ResultSet.TYPE_SCROLL_INSENSTIVE:滚动结果集,但结果集数据不会跟随数据库变化;
  • ResultSet.TYPE_SCROLL_SENSITIVE:滚动结果集,结果集数据跟随数据库变化,但没有数据库驱动会支持它。

      resultSetConcurrency参数的可选值:

  • CONCUR_READ_ONLY:结果集是只读的,不能通过结果集反向影响数据库;
  • CONCUR_UPDATABLE:结果集时可更新的,对结果集的更新可以反向影响数据库。

   【2】获取结果集元数据:

  • 得到元数据:rs.getMetaData(),返回值为ResultSetMetaData;
  • 获取结果集列数:int  getColumnCount();
  • 获取指定列的名:String  getColumnName();

   【3】结果集特征:当使用Connection的createStatement时,已经确定了statement生成的结果集时什么特征。

  • 是否可滚动;
  • 是否敏感;
  • 是否可更新;

   createStatement()生成的结果集:不滚动、不敏感、不可更新。

6、ResultSet之获取列数据

   可以通过next()方法使ResultSet游标向下移动,当游标移动到你需要的行时,就可以获取该行的数据了,ResultSet提供了一系列的获取数据的方法:

  • String  getString(int  columnIndex):获取指定列的String类型数据;
  • int  getInt(int  columnIndex):获取指定列的int类型数据;
  • double  getDouble(int  columnIndex):获取指定列的double类型数据;
  • boolean  getDouble(int  columnIndex):获取指定列的boolean类型数据;
  • Object  getObject(int  columnIndex):获取指定列的SObject类型数据;

   上面方法中,参数columnIndex表示列的索引,列索引从1开始,而不是0,这一点与数组不同。如果你清楚当前列的数据类型,那么可以使用getInt()方法来获取,如果你不清楚类的类型,那么你应该使用getObject()方法来获取。

   ResultSet还提供了一套通过列名来获取列数据的方法:

  • String  getString(String  columnIndex):获取名称为columnIndex的列的String类型数据;
  • int  getInt(String  columnIndex):获取名称为columnIndex的列的int类型数据;
  • double  getDouble(String  columnIndex):获取名称为columnIndex的列的double类型数据;
  • boolean  getDouble(String  columnIndex):获取名称为columnIndex的列的boolean类型数据;
  • Object  getObject(String  columnIndex):获取名称为columnIndex的列的SObject类型数据;
三、PreparedStatement

1、什么是SQL攻击

   在需要用户输入的地方,用户输入的是SQL语句的片段,最终用户输入的SQL片段与我们DAO中写的SQL语句合成一个完整的SQL语句,

2、演示SQL攻击

   首先我们创建一张表,用来存储用户的信息。

CREATE TABLE user(
	uid	CHAR(32) PRIMARY KEY,
	username	VARCHAR(30) UNIQUE KEY NOT NULL,
	PASSWORD 	VARCHAR(30)
);

INSERT INTO user VALUES('U_1001', 'zs', 'zs');
SELECT * FROM user;

   下面我们写一个login()方法:

public void login(String username, String password) {
		Connection con = null;
		Statement stmt = null;
		ResultSet rs = null;
		try {
			con = JdbcUtils.getConnection();
			stmt = con.createStatement();
			String sql = "SELECT * FROM user WHERE " +
					"username='" + username + 
					"' and password='" + password + "'";
			rs = stmt.executeQuery(sql);
			if(rs.next()) {
				System.out.println("欢迎" + rs.getString("username"));
			} else {
				System.out.println("用户名或密码错误!");
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			JdbcUtils.close(con, stmt, rs);
		}		
	}

下面我们调用这个方法的代码:

login("a' or 'a'='a", "a' or 'a'='a");

  这个行当前回事我们登录成功!因为输入的用户名和密码是SQL片段,最终与我们的login()方法的SQL语句组合在一起。组合后的SQL语句:

SELECT * FROM tab_user WHERE username='a' or 'a'='a' and password='a' or 'a'='a'

3、防止SQL攻击

  • 过滤用户输入的数据是否包含非法字符;
  • 分步校验,想使用用户名查询用户,然后校验密码;
  • 使用PreparedStatement;

4、PreparedStatement是什么?

   PreparedStatement叫预编译声明。

   PreparedStatement是Statement的子接口,可以使用PreparedStatement来代替Statement。

   PreparedStatement的好处:

  • 防止SQL攻击;
  • 提高代码的可读性,以及可维护性;
  • 提高效率;

5、PreparedStatement的使用

  • 使用Connection的prepareStatement(String  sql):即创建它时就让它与一条SQL模板绑定;
  • 调用PreparedStatement的setXxx()系列方法为问号设置;
  • 调用executeUpdate()或executeQuery()方法,注意调用无参数的方法;

String sql = "SELECT *FROM tab_stuent WHERE s.name=?";
PreparedStatement ps = con.prepareStatement(sql);
ps.setString(1,"s_1001");
ResultSet rs = ps.executeQuery();
rs.close();
ps.clearParameters();
<pre name="code" class="java">ps.setString(1,"s_1002");
ResultSet rs = ps.executeQuery();

    在使用Connection创建PreparedStatement对象时需要给出一个sql模板,所谓SQL模板就是有?的SQL语句,其中?代表参数。 

   在得到PreparedStatement对象后,调用它的setXxx()方法为?赋值,这样就可以把模板变成一条完整的SQL语句,然后再调用PreparedStatement的executeQuery()方法获取ResultSet对象。

   注意PreparedStatement对象独有的executeQuery()方法是没有参数的,而Statement对象的executeQuery()是需要参数的(SQL语句)。因为在创建PreparedStatement对象时已经与一条SQL模板绑定在一起了,所以调用它的executeQuery()和executeUpdate()方法时就不需要参数了。

   PreparedStatement对象最大的好处是,重复使用同一模板,给与不同的参数来重复的使用它,这才是真正提高效率的原因。

   所以,建议大家在今后的开发中,无论什么情况都去使用PreparedStatement,而不是使用Statement。

四、JdbcUtils工具类

1、JdbcUtils的作用:

   你也看到了,连接数据库的四大参数:驱动类、URL、用户名、密码,这些参数斗鱼特定的数据库关联,如果将来想要改变数据库,那么就要去修改四大参数,为了不修改代码,我们写一个jdbcUtils类,让他从配置文件中读取配置参数,然后创建连接对象。

2、JdbcUtils代码:

  • JdbcUtils.java

public class JdbcUtils{
   //配置文件路径
   private static final String dbconfig = "dbconfig.properties";

   //对应配置文件路径
   private static Properties prop = new Properties();

   //把配置文件内容加载到prop对象中。因为是放到static块中,所以加载操作只会在JdbcUtils类被加载时完成对配置文件的加载。
   static{
      try{
         InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(dbconfig);
         prop.load(in);
         Class.forName(prop.getProperty("driverClassName"));
      }catch(Exception e){
         throw new RuntimeException(e);
      }
   }

   public static Connection(){
      try{
         return DriverManager.getConnection(prop.getProperty("url"),prop.getProperty("username"),prop.getProperty("password"));
      }catch(Exception e){
         throw new RuntimeException(e);
      }
   }
}

  • dbconfig.properties

<span style="color:#000000;">driverClassName=</span><span style="color:#2a0ff;">com.mysql.jdbc.Driver</span><p><span style="color:#000000;">url=</span><span style="color:#2a0ff;">jdbc:mysql://localhost:3306/mydb1?useUnicode=true&characterEncoding=UTF8</span></p><p><span style="color:#000000;">username=</span><span style="color:#2a0ff;">root</span></p><p><span style="color:#000000;">password=</span><span style="color:#2a0ff;">123</span></p>

五、时间类型

1、Java中的时间类型:

   java.sql包下给出三个与数据库相关的日期时间类型,分别是:

  • Date:表示日期,只有年月日,没有时分秒,会丢失日期;
  • Time:表示时间,只有时分秒,没有年月日,会丢失日期;
  • Timestamp:表示时间戳,有年月日时分秒,以及毫秒;

   这三个类都是java.util.Date的子类。

2、时间类型相互转换:
  • java.util.Date--->java.sql.Date、Time、Timestamp

           把util包中的Date转换成毫秒值,使用毫秒值创建sql包中的Date、Time、Timestamp。

           java.util.Date  date  =  new  java.util.Date();

           long  l  =  date.getTime();

           java.sql.Date  date  =  new  java.sql.Date( l );

  • java.sql.Date、Time、Timestamp--->java.util.Date

           因为java.sql.Date是java.util.Date的子类,所以这类转换不用处理。


六、大数据


1、什么是大数据?

   所谓的大数据,就是大的字节数据,或大的字符数据。标准SQL中提供了如下类型来保存大数据的类型:

类型

长度

tinyblob

28--1B256B

blob

216-1B64K

mediumblob

224-1B16M

longblob

232-1B4G

tinyclob

28--1B256B

clob

216-1B64K

mediumclob

224-1B16M

longclob

232-1B4G

 

   但是SQL中没有提供tinyclob、clob、mediumclob、longclob四种类型,而是使用如下四种类型来处理文本大数据:

类型

长度

tinytext

28--1B256B

text

216-1B64K

mediumtext

224-1B16M

longtext

232-1B4G

2、向数据库写数据

   首先我们需要创建一张表,表中要有一个mediumblob类型的字段:

CREATE TABLE stu(id INT PRIMARY KEY AUTO_INCREMENT,
                 filename VARCHAR(100),
                 data MEDIUMBLOB
                 );

   向数据库插入二进制数据需要使用PreparedStatement对象的setBinaryStream(int,InputStream)方法来完成:

con = JdbcUtils.getConnection();
String sql = "insert into stu(filename,data) values(?,?)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1,"a.jpg");
//得到一个输入流对象
InputStream in = new FileInputStream("c\\:a.jpg")
//为第二个参数复制为流对象
pstmt.setBianryStream(2,in);
pstmt.executeUpdate();

   读取二进制数据,需要在查询后使用ResultSet类的getBinaryStream()方法来获取流对象。也就是说PreparedStatement有setXXX(),那么ResultSet就有getXXX()。

con = JdbcUtils.getConnection();
String sql = "select * filename,data from tab_bin where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1,1);
rs = pstmt.executeQuery();

String filename = rs.getString("filename");
OutputStream out = new FileOutputStream("f:\\"+filename);

InputStream in = rs.getBinaryStream("data");
IOUtils.copy(in,out);
out.close);

   还有一种方法,就是 要把存储的数据包装成Blob类型,然后调用PreparedStatement的setBlob()方法来设置数据:

con = JdbcUtils.getConnection();
String sql = "insert into tab_bin(filename,data) values(?,?)":
pstmt = con.prepareStatement(sql);
pstmt.setString(1,"a.jpg");

File file = new File("f:\\a.jpg");
byte[] datas = FileUtils.getBytes(file);//获取文件中的数据
Blob blob = new SerialBlob(datas);//创建Blob对象
pstmt.setBlob(2,blob);//设置blob类型的参数
pstmt.executeUpdate();

<p><span style="color:#000000;">con = JdbcUtils.</span><span style="color:#000000;">getConnection</span><span style="color:#000000;">();</span></p><p><span style="color:#000000;">String sql = </span><span style="color:#2a0ff;">"select filename,data from tab_bin where id=?"</span><span style="color:#000000;">;</span></p><p><span style="color:#000000;">pstmt = con.prepareStatement(sql);</span></p><p><span style="color:#000000;">pstmt.setInt(1, 1);</span></p><p><span style="color:#000000;">rs = pstmt.executeQuery();</span></p><p><span style="color:#000000;">rs.next();</span></p><p></p><p><span style="color:#000000;">String filename = rs.getString(</span><span style="color:#2a0ff;">"filename"</span><span style="color:#000000;">);</span></p><p><span style="color:#000000;">File file = </span><span style="color:#7f055;">new</span><span style="color:#000000;"> File(</span><span style="color:#2a0ff;">"F:\\"</span><span style="color:#000000;"> + filename) ;</span></p><p><span style="color:#000000;">Blob blob = rs.getBlob(</span><span style="color:#2a0ff;">"data"</span><span style="color:#000000;">);</span></p><p><span style="color:#7f055;">byte</span><span style="color:#000000;">[] datas = blob.getBytes(0, (</span><span style="color:#7f055;">int</span><span style="color:#000000;">)file.length());</span></p><p><span style="color:#000000;">FileUtils.</span><span style="color:#000000;">writeByteArrayToFile</span><span style="color:#000000;">(file, datas);</span></p>

七、批处理


1、Statement批处理

   批处理就是一批一批的处理,而不是一个一个的处理。

   当你有10条SQL语句要执行时,一次想服务器发送一条SQL语句,这么做效率很差! 处理的方案就是批处理,即一次向服务器发送多条SQL语句,然后由服务器一次性处理。

   批处理只针对增、删、改语句,对查询没什么意义。

   可以多次调用Statement的addBatch(String  sql)方法,把需要执行的所有SQL语句添加到一个" 批 "中,然后调用Statement类的executeBatch()方法来执行当前"批"中的语句。

for(int x=0;x<10;x++){
   String number = "s_10"+x;
   String name = "stu"+x;
   int age = 20+x;
   String gender = x%2?"male":"female";
   String sql = "insert into stu values('"+number+"','"+name+"',"+age+",'"+gender+"')";
   stmt.addBatch(sql);//stmt内部有一个集合,用来装载sql语句
}
stmt.executeBatch();

   当执行了"批"之后,"批"中的SQL语句就会被清空!!也就是说连续两次调用executeBatch()相当于调用一次。

   还可以在执行"批"之前,调用Statement 的 clearBatch() 的方法来清空" 批 "。

2、PreparedStatement批处理

   PreparedStatement的批处理有所不同,因为每个PreparedStatement对象都绑定一条SQL模板。所以向PreparedStatement中添加的不是SQL语句,而是给"?"赋值。

con = JdbcUtils.getConnection();
String sql = "insert into stu values(?,?,?,?)";
pstmt = con.prepareStatement(sql);
for(int x;x<10;x++){
   pstmt.setString(1,"s_10"+x);
   pstmt.setString(2,"stu"+x);
   pstmt.setInt(3,20+x);
   pstmt.setString(4,x%2==0?"male":"female");
   pstmt.addBatch();
}
pstmt.executeBatch();


八、事务


(一)、事务概述


1、什么是事务?

   银行转账!张三转1000元到李四的账户,这其实需要两条SQL语句:给张三的账户减去1000元,给李四的账户加上1000元。

   如果在第一条SQL语句执行成功后,在执行第二条SQL语句之前,程序中断(可能抛出某个异常,或其他原因),那么李四的账户没有加上1000元,但是张三的账户减去了1000元,这样肯定不行。

   事物的多个操作,要么是完全成功,要么是完全失败,不可能出现成功一半的情况。

2、事务的四大特性

  • 原子性(Atomicity):事务中所有操作是不可分隔的原子单位。事务要么完全成功,要么完全失败。
  • 一致性(Consistency):事务执行后,数据库状态与其他业务规则保持一致。无论成功与否,参与转账的两个账户余额之和是不变的。
  • 隔离性(Isolation):在并发操作中,不同事务之间应该隔离开来,是每个并发中的事务不会互相干扰。
  • 持久性(Durability):一旦事务提交成功,事务中的所有数据操作都必须被持久化到数据库中,即使提交事务之后数据库马上崩溃,在数据库重启时,也必须通过某种机制恢复数据。

3、MySQL中的事务

   在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。

  • 开启事务:start    transction;
  • 结束事务:commit  或  rollback;

   在执行SQL语句之前,先执行start  transction,这就开启了一个事务(事务起点),然后可以去执行多条SQL语句。最后结束事务,commit表示提交,即事务中的多条SQL语句所作出的影响会持久化到数据库中。或者,rollback表示回滚,即回滚到事务起点,之前的所有操作都被撤销。


(二)、JDBC事务


在JDBC中处理事务都是通过Connection完成的。

同一事务中所有的操作,都是使用同一个Connection对象!

1、JDBC中的事务 

   Connection的三个方法与事务相关:

  • setAutoCommit(boolean  b):设置为是否为自动提交事务,如果true(默认值为true)表示自动提交,也就是每条执行的SQL语句都是一个单独的事务;如果设置为false,那么就相当于开启了事务了。
  • commit():提交结束事务。
  • rollback():回滚结束事务。

   JDBC处理事务的代码格式:

        try{
           con.setAutoCommit(false);//开启事务
           ...
           ...
           con.commit();//try的最后提交事务
        }catch(){
           con.rollback();//抛出异常后回滚事务
        }

   示例:

public void transfer(boolean b){
   Connection con = null;
   PreparedStatement pstmt = null;
   try{
      con = JdbcUtils.getConnection();

      //设置为手动提交事务,即开启了事务。
      con.setAutoCommit(false);

      String sql = "update account set balance=balance+? where id=?";
      pstmt = con.prepareStatement(sql);

      //操作
      pstmt.setDouble(1,-10000);
      pstmt.setInt(2,1);
      pstmt.executeUpdate();

      //如果出现了异常就回滚事务。
      if(b){
         throw new Exception();
      }

<pre name="code" class="java">      pstmt.setDouble(1,-10000);
      pstmt.setInt(2,1);
      pstmt.executeUpdate();

      //提交事务
      con.commit();
}catch(Exception e){
//回滚事务
if(con!=null){
try{
con.rollback();
}catch(SQLException ex){}
}
throw new RuntimeException();
}finally{
JdbcUtils.close(con,pstmt);
}
}

 
2、保存点 

   保存点是JDBC3.0的东西,当要求数据库服务器支持保存点方式的回滚。

   检验数据库服务器是否支持保存点:

  • Boolean  b  =  con.getMetaData().supportsSavepoints();

   保存点的作用是允许事务回滚到指定的保存点位置。在事务中设置好保存点,然后回滚时可以选择回滚到指定的保存点,而不是回滚整个事务。注意:回滚到指定保存点并没有结束事务,只有回滚了整个事务才算结束事务

   Connection类的设置保存点,以及回滚到指定保存点方法:

  • 设置保存点:SavePoint  setSavePoint();
  • 回滚到指定保存点:void  rollback(Savepoint);

(三)、事务隔离级别

1、事务的并发读问题

  • 脏读:读取到另一个事务未提交数据;
  • 不可重复读:两次读取不一致;
  • 幻读(虚读):读到另一事务已提交数据;

2、并发事务问题

   因并发事务导致的问题大致5类,其中两类是更新问题,三类是读问题。

  • 脏读(dirty  read):读取到另一个事务的未提交数据,即读取到了脏数据;
  • 不可重复读(unrepeatable  read):对同一记录的两次读取不一致,因为另一事物对该记录做了修改;
  • 幻读(phantom  read):对同一张表的两次查询不一致,因为另一事务插入了一条记录;

   不可重复读和幻读的区别:

  • 不可重复读是读取到了另一事务的更新;
  • 幻读是读取到了另一事务的插入(MySQL中无法测试到幻读);

3、四大隔离级别

   四个等级的事务隔离级别,在相同数据环境下,使用相同的数据输入执行相同的工作,根据不同的隔离级别,可以导致不同的结果。不同事务隔离级别能够解决的数据并发问题能力是不同的。

 【1】SERIALIZABLE(串行化)

  • 不会出现任何并发问题,因为它对同一数据的访问时串行的,非并发访问;
  • 性能最差;

 【2】REPEATABLE READ(可重复读)---- MySQL

  • 防止脏读和不可重复读,不能处理幻读问题;
  • 性能比SERIALIZABLE好;

 【3】READ COMMITTED(读一提交数据)---- Oracle

  • 防止脏读,没有处理不可重复读,也没有处理幻读;
  • 性能比REPEATABLE READ好;

 【4】READ UNCOMMITTED(读未提交数据)

  • 可能出现任何事物并发问题;
  • 性能最好;

4、MySQL的隔离级别

   MySQL的隔离级别为Repeatable read,可以通过下面语句查看:

  • select  @@tx_isolation

   也可以通过下面语句来设置当前链接的隔离级别:

  • set  transction  isolationleve[ 4选1 ]

5、JDBC设置隔离级别

   con.setTransctionIsolation(int  level),参数可选值如下:

  • Connection.TRANSCTION_READ_UNCOMMITTED;
  • Connection.TRANSCTION_READ_COMMITTED;
  • Connection.TRANSCTION_REPEATABLE_READ;
  • Connection.TRANSCTION_SERIALIZABLE;

九、数据库连接池

(一)、数据库连接池

1、数据库连接池的概念

   用池来管理Connection,这样可以重复使用Connection。有了池,所以我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法,把Connection归还给池。池就可以再利用这个Connection对象了。

2、JDBC数据库连接池接口(DataSource)

   Java为数据库连接池提供了公共的接口:javax.sql.DataSource,各个厂商可以让自己的连接池实现这个接口,这样应用程序可以方便的切换不同厂商的连接池。

3、自定义连接池(ItcastPool)

   分析:ItcastPool需要有一个List,用来保存连接对象。在ItcastPool的构造器中创建5个连接对象放到List中!当有人调用了ItcastPool的getConnection()方法时,那么就从List拿出一个返回。当List中没有连接可用时,抛出异常。

   我们需要对Connection的close()方法进行增强,所以我们需要自定义ItcastConnection类,对Connection进行装饰,即对close()方法进行增强。因为需要在调用close()方法把连接归还给池,所以ItcastConnection类需要拥有对池对象的引用,并且池还要提供归还的方法。

(二)、DBCP

1、什么是DBCP?

   DBCP是Apache提供的一款开源免费的数据库连接池。

   Hibernate3.0 之后不再对DBCP提供支持,因为Hibernate声明DBCP有致命的缺陷。

2、DBCP的使用

   public  void  fun() throws  SQLException{

         BasicDataSource  ds  =  new  BasicDataSource();

         ds.setUsername(" root ");

         ds.setPassword(" 123 ");

         ds.setUrl(" jdbc:mysql://localhost:3306/mydb ");

         ds.setDriverClassName(" com.mysql.jdbc.Driver ");

          ds.setMaxActive(20);  //最大连接数

          ds.setMaxIdle(10);  //最大空闲连接数

          ds.setInitialSize(10);  //初始化连接数

          ds.setMinIdle(2);  //最小空闲连接数

          ds.setMaxWaite(1000);  //最大等待毫秒数

      

          Connection  con  =  ds.getConnection();

          con.close();

   }

3、DBCP的配置信息

  • 基本配置

     driverClassName=com.mysql.jdbc.Driver

      url=jdbc:mysql://localhost:3306/mydb1

      username=root

      password=123

  • 初始化池大小,即一开始池中就有10个连接对象(默认值为0)

      initialSize=0

  • 最大连接数,如果设置maxActive = 50时,池中最多可以有50个连接,当然这50个连接中包含被使用的和没被使用的(空闲)

      maxActive=8

  • 最大空闲连接数,默认值为8,如果设置负数,表示没有吸纳之

      maxIdle=8

  • 最小空闲连接数,默认值为0

      minIdle=0

  • 最大等待时间,默认值为-1,表示无限等待,不会抛出异常

      maxWait=-1

  • 连接属性,就是原来放在URL后面的参数,可以使用connectionProperties来指定,如果已经在URL后面指定了那么就不用再这里指定了。

       useServerPrepstmts=true  ---- MySQL开启预编译功能

       cachePrepstmts=true  ---- MySQL开启缓存PreparedStatement功能

       prepStmtCacheSize=50  ---- 缓存preparedStatement的上限

       preStmtCacheSqlLimit=300  ---- 当SQL模板大于300时,就不用缓存它

  • 连接的默认提交方式,默认值为true

       defaultAutoCommit=true

  • 连接是否为只读连接。Connection有一对方法:setReadOnly(boolean  b)和isReadOnly(),如果是只读连接,那么你只能用这个链接来查询,指定连接为只读是为了优化,与并发事务有关。

       defaultReadOnly=false

  • 指定事务的隔离级别

       defaultTransctionIsolation=REPEATABLE_READ

(三)、C3P0

1、C3P0简介

   C3P0也是开源免费的连接池!C3P0倍很多人看好!

2、C3P0使用

   C3P0中的池类是ComboPooledDataSource

public void function()throws PropertyVetoException,SQLException{
   ComboPooledDataSource ds = new ComboPooledDataSource();
   ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
   ds.setUser("root");
   ds.setPassword("123");
   ds.setDriverClass("com.mysql.jdbc.Driver");

   ds.setAcquireIncrement(5);//每次的增量为5
   ds.setInitialPoolSize(20);//初始化连接数
   ds.setMinPoolSize(2);//最小连接数
   ds.setMaxPoolSize(50);//最大连接数

   Connection  con = ds.getConnection();
   con.close();
}

   配置文件要求:

  • 文件名称:必须叫c3p0-config.xml
  • 文件位置:必须在src下

   C3P0也可以指定配置文件,而且配置文件可以是properties,也可以是xml的。但是C3P0的配置文件名必须叫c3p0-config.xml,并在必须放在类路径下。

<?xml version="1.0" encoding="UTF-8"?>
   <c3p0-config>
      <default-config>
         <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb</property>
         <pre name="code" class="html">
         <property name="driverClass">com.mysql.jdbc.Driver</property>

         <property name="user">root</property>

         <property name="password">123</property>

         <property name="acquireIncrement">3</property>

         <property name="initialPoolSize">10</property>

         <property name="minPoolSize">2</property>

         <property name="maxPoolSize">10</property>

</difault-config>
<named-config name="oracle-donfig">
 <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb</property>

<pre name="code" class="html">         <property name="driverClass">com.mysql.jdbc.Driver</property>

         <property name="user">root</property>

         <property name="password">123</property>

         <property name="acquireIncrement">3</property>

         <property name="initialPoolSize">10</property>

         <property name="minPoolSize">2</property>

         <property name="maxPoolSize">10</property>

</named-config> </c3p0-config> 

 

   C3P0的配置文件中可以配置多个连接信息,可以给每个配置起个名字,这样可以方便通过配置名称来切换配置信息。上面文件中默认配置为mysql配置,名为oracle-config的配置也是mysql的配置。

<p><span style="color:#7f055;">//default默认配置
</span></p><p><span style="color:#7f055;">public</span><span style="color:#000000;"> </span><span style="color:#7f055;">void</span><span style="color:#000000;"> fun2() </span><span style="color:#7f055;">throws</span><span style="color:#000000;"> PropertyVetoException, SQLException {</span></p><p><span style="color:#000000;">   ComboPooledDataSource ds = </span><span style="color:#7f055;">new</span><span style="color:#000000;"> ComboPooledDataSource();</span></p><p><span style="color:#000000;">   Connection con = ds.getConnection();</span></p><p><span style="color:#000000;">   System.</span><span style="color:#00c0;">out</span><span style="color:#000000;">.println(con);</span></p><p><span style="color:#000000;">   con.close();</span></p><p><span style="color:#000000;">}</span></p>

<p><span style="color:#7f055;"><span style="color:#7f055;">//切换为oracle-config配置</span>
</span></p><p><span style="color:#7f055;">public</span><span style="color:#000000;"> </span><span style="color:#7f055;">void</span><span style="color:#000000;"> fun2() </span><span style="color:#7f055;">throws</span><span style="color:#000000;"> PropertyVetoException, SQLException {</span></p><p><span style="color:#000000;">   ComboPooledDataSource ds = </span><span style="color:#7f055;">new</span><span style="color:#000000;"> ComboPooledDataSource(</span><span style="color:#2a0ff;">"orcale-config"</span><span style="color:#000000;">)</span><span style="color:#000000;">;</span></p><p><span style="color:#000000;">   Connection con = ds.getConnection();</span></p><p><span style="color:#000000;">   System.</span><span style="color:#00c0;">out</span><span style="color:#000000;">.println(con);</span></p><p><span style="color:#000000;">   con.close();</span></p><p><span style="color:#000000;">}</span></p>

(四)Tomcat配置连接池


1、Tomcat配置JNDI资源

   JNDI(Java Naming  and  Directory  Interface),Java命名和目录接口。

   JNDI的作用就是:在服务器上配置资源,然后通过统一的放置来获取配置资源。

   下图是Tomcat文档提供的:


  配置JNDI资源需要到<Context>元素中配置<Resource>子元素:

  • name:指定资源的名称,这个名称可以随便给,在获取资源时需要这个名称;
  • factory:用来创建资源的工厂,这个值基本是固定的。不用修改;
  • type:资源的类型,我们要给出的类型当然是连接池的类型;
  • bar:表示资源的属性,如果资源存在名为bar的属性,那么就配置bar的值。对于DBCP连接池而言,你需要配置的不是bar,因为没有bar属性,而应该去配置url、username等属性。

<p><Context>  </p><p>  <Resource name="mydbcp" </p><p>			type="org.apache.tomcat.dbcp.dbcp.BasicDataSource"</p><p>			factory="org.apache.naming.factory.BeanFactory"</p><p>			username="root" </p><p>			password="123" </p><p>			driverClassName="com.mysql.jdbc.Driver"    </p><p>			url="jdbc:mysql://127.0.0.1/mydb1"</p><p>			maxIdle="3"</p><p>			maxWait="5000"</p><p>			maxActive="5"</p><p>			initialSize="3"/></p><p></Context>  
</p>

<p><Context>  </p><p>  <Resource name="myc3p0" </p><p>			type="com.mchange.v2.c3p0.ComboPooledDataSource"</p><p>			factory="org.apache.naming.factory.BeanFactory"</p><p>			user="root" </p><p>			password="123" </p><p>			classDriver="com.mysql.jdbc.Driver"    </p><p>			jdbcUrl="jdbc:mysql://127.0.0.1/mydb1"</p><p>			maxPoolSize="20"</p><p>			minPoolSize ="5"</p><p>			initialPoolSize="10"</p><p>			acquireIncrement="2"/></p><p></Context>  
</p>

2、获取资源

   配置资源的目的当然是为了获取资源,只要你启动了Tomcat,那么就可以在项目任何类中通过JDNI获取资源的方式来获取资源了。

   下图是Tomcat文档提供的,与上面Tomcat提供的配置资源时对应的:

   获取资源:

  • Context:javax.naming.Context;
  • InitialContext:javax.naming.InitialContext;
  • lookup(String  str):获取资源的方法,其中" java:comp/env "是资源的入口(这是固定的名称),获取过来的还是一个Context,这说明需要在获取到的Context上进一步进行获取。" bean/MyBeanFactory "对应<Resource>中配置的name值,这回获取的就是资源对象了。

<p><span style="color:#000000;">Context cxt = </span><span style="color:#7f055;">new</span><span style="color:#000000;"> InitialContext(); </span></p><p><span style="color:#000000;">DataSource ds = (DataSource)cxt.lookup(</span><span style="color:#2a0ff;">"java:/comp/env/</span><span style="color:#2a0ff;">mydbcp</span><span style="color:#2a0ff;">"</span><span style="color:#000000;">);</span></p><p><span style="color:#000000;">Connection con = ds.getConnection();</span></p><p><span style="color:#000000;">System.</span><span style="color:#00c0;">out</span><span style="color:#000000;">.println(con);</span></p><p><span style="color:#000000;">con.close();</span></p>

<p><span style="color:#000000;">Context cxt = </span><span style="color:#7f055;">new</span><span style="color:#000000;"> InitialContext(); </span></p><p><span style="color:#000000;">Context </span><span style="color:#000000;">envC</span><span style="color:#000000;">xt =</span><span style="color:#000000;"> (Context)</span><span style="color:#000000;">cxt.lookup(</span><span style="color:#2a0ff;">"java:/comp/env"</span><span style="color:#000000;">);</span></p><p><span style="color:#000000;">DataSource ds = (DataSource)</span><span style="color:#000000;">env</span><span style="color:#000000;">.lookup(</span><span style="color:#2a0ff;">"</span><span style="color:#2a0ff;">mydbcp</span><span style="color:#2a0ff;">"</span><span style="color:#000000;">);</span></p><p><span style="color:#000000;">Connection con = ds.getConnection();</span></p><p><span style="color:#000000;">System.</span><span style="color:#00c0;">out</span><span style="color:#000000;">.println(con);</span></p><p></p><p><span style="color:#000000;">con.close();</span></p>


   上面两种方式是相同的效果。


十、ThreadLocal


1、ThreadLocal API

   ThreadLocal类只有三个方法:

  • void  set(T  value):保存值
  • T  get():获取值
  • void  remove():移除值

2、ThreadLocal的内部是Map

   ThreadLocal内部其实是一个Map来保存数据。虽然在使用ThreadLocal时只给出了值,没有给出键,其实它内部使用了当前线程作为键。

class MyThreadLocal<T> {
	private Map<Thread,T> map = new HashMap<Thread,T>();
	public void set(T value) {
		map.put(Thread.currentThread(), value);
	}
	
	public void remove() {
		map.remove(Thread.currentThread());
	}
	
	public T get() {
		return map.get(Thread.currentThread());
	}
}


十一、DBUtils


1、DBUtils简介

   DBUtils是Apache Commons组件的一员,开源免费。

   DBUtils是对JDBC的简单封装,但它还是被很多公司使用。

   DBUtils的jar包:dbtutils.jar

2、DBUtils主要类

   DBUtils都是静态方法,一系列的close()方法。

   QueryRunner:

  • update():执行insert、update、delete语句;
  • query():执行select语句;
  • batch():执行批处理;

3、QueryRunner之更新

   QueryRunner的update()方法可以用来执行insert、update、delete语句。

   【1】创建QueryRunner

             构造器:queryRunner()

   【2】update方法

             int  update(Connection  con ,String  sql ,Object...  params)

   还有另一种方式来使用QueryRunner。

   【1】创建QueryRunner

             构造器:QueryRunner( DataSource )

   【2】update方法

             int  update(String  sql ,Object...  params)

   这种方式在创建QueryRunner时传递了连接池对象,那么在调用update()方法时就不用再传递Connection了。

4、ResultSetHandler

   我们知道在执行select语句之后得到的时ResultSet,然后我们还需要对ResultSet进行转换,得到我们最终想要的数据。你可以希望把ResultSet的数据放到一个List中,也可以是一个Map中,或者一个Bean中。

   DBUtils 提供了一个接口ResultSetHandler,它就是用来ResultSet转换成目标类型的工具,你可以自己实现这个接口,把ResultSet转换成你想要的类型。

   DBUtils提供了很多个ResultSetHandler接口的实现,这些实现基本够用,我们通常不用自己去实现ResultSetHandler。

  • MapHandler:单行处理器,把结果转为Map<String,Object>,其中列名为键;
  • MapListHandler:多行处理器,把结果转换为List<Map<String,Object>>;

            

  • BeanHandler:单行处理器,把结果集转换为Bean,该处理器需要Class参数,即Bean的类型;
  • BeanListHandler:多行处理器,把结果集转换为List<Bean>;

            

  • ColumnListHandler:多行单列处理器,把结果集转换为List<Object>,使用ColumnListHandler时需要指定某一列的名称或编号,例如new  ColumnListHandler(" name ")表示把name列的数据放到List中;

            

  • ScalarHandler:单行单列处理器,把结果集转换为Object,一般用于聚集查询。

             


5、QueryRunner之查询

   QueryRunner的查询方法是:

  • public  <T>  T  query(String  sql , ResultSetHandler<T>  rh , Object...  params);
  • public <T> T query(Connection con, String sql, ResultSetHandler<T> rh, Object… params)

   query()方法会通过sql语句和params查询出ResultSet,然后通过rhResultSet转换成对应的类型再返回。

6、QueryRunner之批处理

   QueryRunner还提供了批处理方法:batch()

   我们更新一行记录时需要指定一个Object[]为参数,如果是批处理,那么就要指定Object[][]为参数了。即多个Object[]就是Object[][]了,其中每个Object[]对应一行记录:

public void fun10() throws SQLException {
	DataSource ds = JdbcUtils.getDataSource();
	QueryRunner qr = new QueryRunner(ds);
	String sql = "insert into tab_student values(?,?,?,?)";
	Object[][] params = new Object[10][];[注意,这里是二维数组,这个二维数组有10个一维数组。]//表示 要插入10行记录
	for(int i = 0; i < params.length; i++) {
		params[i] = new Object[]{"S_300" + i, "name" + i, 30 + i, i%2==0?"男":"女"};
	}
	qr.batch[执行批处理](sql, params);
}
如果你的sql server 2000远程连接时,无法打开1433端口,请按照以下顺序进行检查和修正: 1.如果你是win2003,那么一定要安装sql的补丁sp3a 检查你的SQL有没有打补丁,没有的话要打上补丁,检查的方法是在查询分析器中运行: select @@version 如果出来的版本号是8.00.760以下,则表明你未安装sp3的补丁,要装上. SQL补丁下载: 全部补丁的位置 http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&FamilyID=9032f608-160a-4537-a2b6-4cb265b80766 注意下载后,执行的时候是解压,要在解压后的目录中执行setup.bat才是真正的安装 2.SQL Server连接中的四个最常见错误: 一."SQL Server 不存在或访问被拒绝" 这个是最复杂的,错误发生的原因比较多,需要检查的方面也比较多. 一般说来,有以下几种可能性: 1,SQL Server名称或IP地址拼写有误 2,服务器端网络配置有误 3,客户端网络配置有误 要解决这个问题,我们一般要遵循以下的步骤来一步步找出导致错误的原因. ============= 首先,检查网络物理连接 ============= ping 如果 ping 不成功,说明物理连接有问题,这时候要检查硬件设备,如网卡,HUB,路由器等. 还有一种可能是由于客户端和服务器之间安装有防火墙软件造成的,比如 ISA Server.防火墙软件可能会屏蔽对 ping,telnet 等的响应 因此在检查连接问题的时候,我们要先把防火墙软件暂时关闭,或者打开所有被封闭的端口. 如果ping 成功而,ping 失败 则说明名字解析有问题,这时候要检查 DNS 服务是否正常. 有时候客户端和服务器不在同一个局域网里面,这时候很可能无法直接使用服务器名称来标识该服务器,这时候我们可以使用HOSTS文件来进行名字解析, 具体的方法是: 1.使用记事本打开HOSTS文件(一般情况下位于C:\WINNT\system32\drivers\etc). 添加一条IP地址与服务器名称的对应记录,如: 172.168.10.24 myserver 2.或在 SQL Server 的客户端网络实用工具里面进行配置,后面会有详细说明. ============= 其次,使用 telnet 命令检查SQL Server服务器工作状态 ============= telnet 1433 如果命令执行成功,可以看到屏幕一闪之后光标在左上角不停闪动,这说明 SQL Server 服务器工作正常,并且正在监听1433端口的 TCP/IP 连接 如果命令返回"无法打开连接"的错误信息,则说明服务器端没有启动 SQL Server 服务, 也可能服务器端没启用 TCP/IP 协议,或者服务器端没有在 SQL Server 默认的端口1433上监听.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值