Hibernate笔记一

Hibernate介绍

Hibernate是轻量级JavaEE应用的持久层解决方案,是一个关系数据库ORM框架.Hibernate的持久化方案,将用户从原始的JDBC底层SQL访问中解放出来,用户无须关注底层数据库操作,只要通过操作映射到数据表的Java对象,就可以对数据库进行增删改查

ORM (Object Relational Mapping对象关系映射)
ORM 就是通过将Java对象映射到数据库表,通过操作Java对象,就可以完成对数据表的操作

流行数据库框架 
1. JPA(Java Persistence API) : 通过注解描述对象与数据表映射关系 (只有接口规范)
2. Hibernate : 最流行ORM框架,通过对象-关系映射配置,可以完全脱离底层SQL , Hibernate实现JPA规范 
3. MyBatis : 本是apache的一个开源项目 iBatis,支持普通 SQL查询,存储过程和高级映射的优秀持久层框架 (企业主流)
    * MyBaits 并不是完全ORM , 需要在xml中配置SQL语句
4. Apache DBUtils(超链接到DBUtils那节笔记里面去)
5. Spring JDBCTemplate

SQL语句封装程度 Hibernate > MyBatis > Apache DBUtils 、Spring JDBCTemplate

Hibernate中的ORM实现

数据库中的表与java中的类对应
表中的记录是与类中的对象对应
表中的字段是与类中的属性对应

ORM对应关系.png

Hibernate体系结构

Hibernate架构.png

Hibernate目录结构

Hibernate目录结构.png

Hibernate使用

1.导入jar包

导包的内容参见上一步,目录结构中导入即可

特别介绍: log4j(链接上log4j的单独的笔记内容)

2.编写类和关系映射配置xx.hbm.xml

public class Customer {
    private int id;
    private String name;
    private int age;
    private String city;
    ...
}

hibernate 完全ORM,只需要操作Customer类对象, 自动生成SQL 操作customer 表
但是需要为实体类和数据表进行关系映射配置
1.在实体类所在的包下创建名为:类名.hbm.xml文件,eg:Customer.hbm.xml
2.配置规则参见 hibernate3.jar org/hibernate/hibernate-mapping-3.0.dtd





















配置属性到列映射时,指定类型,类型有三种写法
第一种 java类型 java.lang.String
第二种 hibernate类型 string
第三种 SQL类型 varchar(20)

3.配置核心配置文件hibernate.cfg.xml

Hibernate框架支持两种 Hibernate属性配置方式
1.hibernate.properties
采用properties方式,必须手动编程加载 hbm文件或者 持久化类
2.hibernate.cfg.xml
采用XML配置方式,可以通过配置添加hbm文件
规则参见 hibernate3.jar /org/hibernate/hibernate-configuration-3.0.dtd

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <!-- 会话连接工厂,建立数据库连接需要SessionFactory -->
    <session-factory>
        <!-- JDBC连接基本参数 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql:///hibernatetest</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">1234</property>
        <!-- 配置数据库方言,便于生成一些与数据库相关SQL方言 -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <!-- DDL策略   可以根据需要自动创建数据表 -->
        <property name="hibernate.hbm2ddl.auto">update</property>
        <!-- 将SQL语句 输出到控制台 -->
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>

        <!-- 导入映射的po类的xx.hbm.xml映射文件-->            
        <mapping resource="cn/itcast/domain/Customer.hbm.xml"></mapping>
    </session-factory>
</hibernate-configuration>

注意:
配置文件必须放在根目录下
通常采用方式2来配置

编程操作使用Hibernate框架

web层的javabean叫vo viewobject

service层 bo business object

dao层 po 持久化对象
po类需要有个无参构造,get/set方法,私有化属性,属性使用包装类型,不要用基本类型,类不能为final(因为要为他生成代理),
还需要有一个与表中主键映射的字段


hbm映射介绍

pojo是个啥? 视频两分钟的时候介绍了下

JDBC笔记二

1. JDBC批处理

Statement 和 PreparedStatement 都提供批处理。
批处理:批量处理sql语句。
Statement的批处理,可以一次性执行不同的sql语句。应用场景:系统初始化(创建数据库,创建不同表)
PreparedStatement 的批处理,只能执行一条sql语句,实际参数可以批量。应用场景:数据的初始化

1.1 Statement

addBatch(sql)  ,给批处理缓存中添加sql语句。
clearBatch();  清空批处理缓存。
executeBatch() , 执行批处理缓存所有的sql语句。注意:执行完成之后缓存中的内容仍然存在。

1.2 PreparedStatement

addBatch()  , 将实际参数批量设置缓存中。注意:获得预处理之前必须提供sql语句。

mysql 默认没开启批处理。
通过URL之后参数开启, ?rewriteBatchedStatements = true

2. 事务

2.1 什么是事务

  • 事务:一组业务逻辑操作,要么全部成功,要么全部不成功。
  • 事务特性:ACID
    • 原子性:一个事务是不可划分的一个整体。要么成功,要么不成功。
    • 一致性:事务操作前后数据一致。(数据完整)。转账前后,两个人和一样的。
    • 隔离性:多个事务对同一个内容并发操作。
    • 持久性:事务提交,操作成功了。不能改变了。保存到数据库中了。
  • 隔离问题
    • 脏读:一个事务 读到 另一个 事务 没有提交的数据。
    • 不可重复读:一个事务 读到 另一个事务 已经提交的数据。(update更新)
    • 虚读(幻读):一个事务 读到 另一个事务 已经提交的数据。(insert插入) –理论时
  • 事务隔离级别:用于解决隔离问题
    1. 读未提交:read uncommitted,一个事务读到另一个事务没有提交的数据。存放问题:3个
    2. 读已提交:read committed,一个事务读到另一个事务提交的数据。解决:脏读,存在2个问题
    3. 可重复读:repeatable read ,一个事务中读到数据重复的。及时另一个事务已经提交。解决:脏读、不可重复读,存放1个问题。
    4. 串行化,serializable,单事务,同时只能一个事务在操作。另一个事务挂起(暂停)。解决:3个问题。
  • 默认隔离级别
    mysql默认隔离级别:repeatable read
    oracle默认隔离级别:read committed
    对比:
    性能:read uncommitted > read committed > repeatable read > serializable
    安全:read uncommitted < read committed < repeatable read < serializable

2.2 事务操作

  • mysql 命令操作
    开启事务:mysql> start transaction; –开启相当于关闭自动提交
    提交事务:mysql> commit; –全部成功
    回滚事务:mysql> rollback; –保证全部不成功
  • jdbc java代码操作【掌握】– JDBC中必须使用Connection连接进行事务操作。
    开启事务:conn.setAutoCommit(false);
    提交事务:conn.commit();
    回滚事务:conn.rollback();

mysql 默认事务提交的,及每执行一条sql语句就是一个事务。
扩展:oracle事务默认不提交,需要手动提交。

2.3 保存点

Savepoint 保存点,用于记录程序执行位置,方便可以随意回滚指定的位置。spring 事务的传播行为
AB整体(必须),CD整体(可选)

Savepoint savepoint = null;
try{
   // 1 开启事务
   conn.setAutoCommit(false);
   A
   B
   // 记录保存点
   savepoint = conn.setSavepoint();
   C
   D

   //2 提交ABCD
   conn.commit();
} catch(){
  if(savepoint != null){
      //CD 有异常,回滚到CD之前
      conn.rollback(savepoint);
      // 提交AB
      conn.commit();
  } else {
     //AB有异常 ,回滚到最开始处
     conn.rollback();
  }
}

2.4 丢失更新

案例

A 查询数据,username = ‘jack’ ,password = ‘1234’
B 查询数据,username=”jack”, password=”1234”
A 更新用户名 username=”rose”,password=’1234’ –> username=”rose”,password=”1234”
B 更新密码 password=”9999” ,username=”jack” –> username=”jack”,password=’9999’
丢失更新:最后更新数据,将前面更新的数据覆盖了。

解决方案:采用锁机制。

乐观锁:丢失更新肯定不会发生。

给表中添加一个字段(标识),用于记录操作版本。
username="jack",password="1234",version="1" ,比较版本号,如果一样,修改版本自动+1.。如果不一样,必须先查询,再更新。

悲观锁:丢失更新肯定会发生。采用数据库锁机制。

读锁:共享锁,大家可以一起读。
    select .... from .... lock in share mode;
写锁:排他锁,只能一个进行写,不能有其他锁(写、读),所有更新update操作丢将自动获得写锁。
    select ... from ... for update;

注意:数据库的锁,必须在事务中使用。
只要事务操作完成(commit|rollback|超时)自动释放锁

3. 事务实例

4. 连接池

1.为什么使用连接池:连接Connection 创建与销毁 比较耗时的。为了提供性能,开发连接池。
2.什么是连接池

javaee规范规定:连接池必须实现接口,javax.sql.DataSource (数据源)
为了获得连接 getConnection()
连接池给调用者提供连接,当调用者使用,此链接只能供调动者是使用,其他人不能使用。
当调用者使用完成之后,必须归还给连接池。连接必须重复使用。

3.自定义连接池
4.第三方连接池

DBCP,apache
C3P0 ,hibernate 整合
tomcat 内置(JNDI)

4.1 DBCP

1.Apache提供的
2.导入jar包

commons-dbcp-1.4.jar 核心包
commons-pool-1.6.jar 依赖包

3.核心类

public class BasicDataSource implements DataSource

4.手动调用

//1 创建核心类
BasicDataSource dataSource = new BasicDataSource();
//2 配置4个基本参数
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///day16_db");
dataSource.setUsername("root");
dataSource.setPassword("1234");
//3 管理连接配置
dataSource.setMaxActive(30);    //最大活动数
dataSource.setMaxIdle(20);        //最大空闲数
dataSource.setMinIdle(10);        //最小空闲数
dataSource.setInitialSize(15);    //初始化个数

5.配置调用

DBCP采用properties文件,key=value ,key为 BasicDataSource属性(及setter获得)
//0 读取配置文件
InputStream is = TestDBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(is);
//1 加载配置文件,获得配置信息
DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);

6.配置文件 dbcpconfig.properties

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day16_db
username=root
password=1234

#<!-- 初始化连接 -->
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000


#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] 
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

4.2 C3P0

1.第三方提供,非常优秀
2.导入jar包

c3p0-0.9.2-pre5.jar 核心包
mchange-commons-java-0.2.3.jar 依赖包
c3p0-oracle-thin-extras-0.9.2-pre5.jar 使用oracle的依赖

3.核心类

ComboPooledDataSource

4.手动调用

//1 核心类 (日志级别:debug info warn  error)
ComboPooledDataSource dataSource = new ComboPooledDataSource();
//2 基本4项
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///day16_db");
dataSource.setUser("root");
dataSource.setPassword("1234");
//3 优化
dataSource.setMaxPoolSize(30);        //最大连接池数
dataSource.setMinPoolSize(10);        //最小连接池数
dataSource.setInitialPoolSize(15);    //初始化连接池数
dataSource.setAcquireIncrement(5);    //每一次增强个数

5.配置调用

加载位置:WEB-INF/classes  (classpath , src)
配置文件名称:c3p0-config.xml
//1 c3p0...jar 将自动加载配置文件。打包后从WEB-INF/classes (src)目录加载名称为c3p0-config.xml的文件
//ComboPooledDataSource dataSource = new ComboPooledDataSource(); //自动从配置文件 <default-config>
ComboPooledDataSource dataSource = new ComboPooledDataSource("itheima"); //手动指定配置文件 <named-config name="itheima"> 

6.配置文件 c3p0-config.xml

<c3p0-config>
    <!-- 默认配置,如果没有指定则使用这个配置 -->
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql:///day16_db</property>
        <property name="user">root</property>
        <property name="password">1234</property>

        <property name="checkoutTimeout">30000</property>
        <property name="idleConnectionTestPeriod">30</property>
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
        <user-overrides user="test-user">
            <property name="maxPoolSize">10</property>
            <property name="minPoolSize">1</property>
            <property name="maxStatements">0</property>
        </user-overrides>
    </default-config> 
    <!-- 命名的配置 -->
    <named-config name="itheima">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql:///day16_db</property>
        <property name="user">root</property>
        <property name="password">1234</property>
    <!-- 如果池中数据连接不够时一次增长多少个 -->
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">20</property>
        <property name="minPoolSize">10</property>
        <property name="maxPoolSize">40</property>
        <property name="maxStatements">0</property>
        <property name="maxStatementsPerConnection">5</property>
    </named-config>
</c3p0-config> 

4.3 JNDI

  • tomcat管理连接池
  • JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口,用于存放java任意对象,给对象进行命名(使用目录结构)。例如:/a/b/c
  • 作用:在多个项目之间共享数据,只需要传递名称,就可以获得对象。
  • 理解:JNDI 就是一个容器,用于存放任意对象。
  • tomcat 将连接池存放 JNDI容器,可以获得使用。使用前提必须通知tomcat进行存放,默认情况下tomcat没有存放。

配置:
1.给tomcat配置数据源(连接池),使用 标签

方式1:%tomcat%/conf/server.xml -->  在<Host>标签下添加<Context>
方式2:%tomcat%/conf/Catalina/localhost/day16.xml  ---> <Context>
    day16/META-INF/Context.xml  在项目的META-INF下创建Context.xml,会自动发布到“方法2”指定位置
Context.xml中的内容:
    <Context>
        <!-- 
            name 存放进去名称
            auth 存放位置
            type 确定存放内容,tomcat将通过指定接口创建实例,底层使用DBCP
            其他都是DBCP属性设置
         -->
      <Resource name="jdbc/itheima" auth="Container" type="javax.sql.DataSource"
                   maxActive="100" maxIdle="30" maxWait="10000"
                   username="root" password="1234" driverClassName="com.mysql.jdbc.Driver"
                   url="jdbc:mysql://localhost:3306/day16_db"/>
    </Context>

2 从JNDI容器获取,在当前项目web.xml配置

<!-- 给当前项目配置,从JNDI容器获得指定名称内容 -->
<resource-ref>
  <res-ref-name>jdbc/itheima</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

3.使用

//0 包名:javax.naming
//1 初始化JNDI容器
Context context = new InitialContext();
//2 获得数据源   固定 “java:/comp/env”
DataSource dataSource = (DataSource)context.lookup("java:/comp/env/jdbc/itheima");

JDBC笔记一

1. JDBC简单应用

public class FirstJDBC {
    public static void main(String[] args) throws Exception {
        // 0.准备变量
        String driver = "com.mysql.jdbc.Driver";// mysql驱动实现类
        String url = "jdbc:mysql://localhost:3306/day15_db";// 确定数据库服务器地址,端口号,使用数据库
        String user = "root";// 登录名称
        String password = "1234";// 登录密码
        // 1.注册驱动
        Class.forName(driver);
        // 2.获得链接
        Connection conn = DriverManager.getConnection(url, user, password);
        // 3.获得语句执行者
        Statement st = conn.createStatement();
        // 4.发送sql语句,查询  结果相当于一个set集合,每一个成员表示数据库表中一条记录
        ResultSet rs = st.executeQuery("select * from t_user ");
        // 5.处理结果
        rs.next();// 移动到第一行
        // getXxx获取某一行的指定列或字段值  getXxx(int 列数),getXxx(String 字段名)
        int id = rs.getInt("id");
        String username = rs.getString("username");
        String userPassword = rs.getString("password");
        System.out.printf("id:"+id+" username:"+username+" password:"+password);
        // 6.释放资源,优先关闭最后使用的
        rs.close();
        st.close();
        conn.close();
    }
}

2. Junit 测试

1.需要导入两个jar包
junit.jar
hamcrest-core.jar
放入libs目录下即可
2.类名alt+enter,然后选择需要添加测试的方法即可

测试用例方法,公共 没有返回值 非静态 方法名自定义 没有参数列表
方法名建议:test方法名()

public class DemoTest {
    private Demo demo;

    @Before  //测试方法执行前
    public void myBefore(){
        System.out.println("之前");
        demo = new Demo();
        //初始化数据
    }
    @After   //测试方法执行后
    public void myAfter(){
        System.out.println("之后");
        //方法资源
    }
    @Test(timeout=1000)  //timeout 设置测试时间,如果超时性能有问题
    public void testAdd() {
        try {
            Thread.sleep(2000);
        } catch (Exception e) {
        }

        int sum = demo.add(1, 2);
        //断言
        Assert.assertEquals(3, sum);
        assertEquals(3, sum);  //使用静态导入的结果
    }
    @Test
    public void testMul() {
        int sum = demo.mul(1, 2);
    }
    @BeforeClass
    public static void myBeforeClass(){
        System.out.println("类之前");

    }
    @AfterClass
    public static void myAfterClass(){
        System.out.println("类之后");
    }
}

3. JDBC工具类

public class JdbcUtils {
    private static String url;
    private static String user;
    private static String password;

    // 这些配置文件的东西只用加载一次就可以了,写在静态代码块中
    static {
        try {
            // 参数配置应该放在配置文件中
            // 1. 加载properties文件
            // 方式1:使用ClassLoader加载资源
            //InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbcInfo.properties");
            // 方式2:使用Class对象加载,必须加上/,表示src
            InputStream is = JdbcUtils.class.getResourceAsStream("/jdbcInfo.properties");
            // 2. 解析配置文件
            Properties properties = new Properties();
            properties.load(is);
            // 3. 获得配置文件中的数据
            String driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            // 4. 注册驱动
            Class.forName(driver);
        } catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    /**
     * 获得连接
     */
    public static Connection getConnection(){
        try {
            Connection conn = DriverManager.getConnection(url, user, password);
            return conn;
        } catch (Exception e){
            // 将编译时异常转换成运行时异常,开发中常见运行时异常
            // throw new RuntimeException(e);
            // 此处可以使用自定义异常
            // 类与类之间进行数据交换时可以使用return返回数据.
            // 也可以使用自定义异常返回值,调用者try{} catch(e){ e.getMessage() 获得需要的数据}
            throw new MyConnectionException(e);
        }
    }

    /**
     * 释放资源
     */
    public static void closeResource(Connection conn, Statement st, ResultSet rs){
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (Exception e){
            throw new RuntimeException(e);
        } finally {
            try {
                if (st != null) {
                    st.close();
                }
            } catch (Exception e){
                throw new RuntimeException(e);
            } finally {
                try {
                    if (conn != null) {
                        conn.close();
                    }
                } catch (Exception e){
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

4. 自定义异常

继承RuntimeException 覆写方法
将编译时异常转换成运行时异常,开发中常见运行时异常
throw new RuntimeException(e);
类与类之间进行数据交换时可以使用return返回数据.
也可以使用自定义异常返回值,调用者try{} catch(e){ e.getMessage() 获得需要的数据}

5. 模板代码

public void demo1(){
    Connection conn = null;
    Statement st = null;
    ResultSet rs = null;

    try {
        conn = JdbcUtils.getConnection();
        // ....
    } catch (Exception e){
        throw new RuntimeException(e);
    } finally {
        // 释放资源
        JdbcUtils.closeResource(conn,st,rs);
    }
}

6. Api详解

6.1 注册驱动

1.0 所有的驱动实现类必须实现规范接口,java.sql.Driver接口
1.1 原始编写方式:DriverManager.registerDriver(new Driver());
    特点:必须导包  import com.mysql.jdbc.Driver; 
        硬编程,内容写死的,无法扩展,不易于数据变迁(更换)
    源码:public class com.mysql.jdbc.Driver implements java.sql.Driver

1.2 建议编写方式:Class.forName("com.mysql.jdbc.Driver");
    特点:指定类如果有static{} 里面的内容将自动执行。
    源码:
        static {
            try {
                java.sql.DriverManager.registerDriver(new Driver());
            } catch (SQLException E) {
                throw new RuntimeException("Can't register driver!");
            }
        }
        mysql Driver实现类,将自己进行注册。
    优点:使用字符串方法加载到内容(注册),之后可以将驱动配置到配置文件中,之后只需要修改配置文件,数据库就更改。
1.3 此行代码可省略,建议不要省略。
    mysql驱动 高版本,将自动加载驱动并注册。
        文件:mysql-connector-java-5.1.22-bin.jar/META-INF/services/java.sql.Driver
        内容:com.mysql.jdbc.Driver 
1.4 错误总结
    * ClassNotFoundException ,是否导入jar包?驱动名称是否正确?
    * java.lang.NoClassDefFoundError   如果配置文件放置位置错误就会报这个异常
1.5 mysql  com.mysql.jdbc.Driver 子类  org.gjt.mm.mysql.Driver
    源码:public class Driver extends com.mysql.jdbc.Driver

6.2 获得连接

2.1 介绍
    使用连接接口:java.sql.Connection,只有获得连接才可以操作数据库。
    通过DriverManager 驱动管理者类获得连接。getConnection(url,user,password)
2.2 url 确定访问数据库位置
    格式#   协议:子协议:子名称
        协议  固定值 -->  jdbc
        子协议  --> 确定数据,例如:mysql、oracle 等
        子名称  --> localhost主机,3306端口,day15_db数据库名称
        参数  --> jdbc:mysql://localhost:3306/day15_db?useUnicode=true&characterEncoding=UTF-8
            设置请求编码,安装如果指定UTF-8,不需要设置的。如果安装时设置的编码为ISO8859-1编码,中文乱码需要如上处理。
    主机默认localhost,端口默认3306
        简写方式 -->  jdbc:mysql:///day15_db
2.3 错误总结
    * Unknown database 'day15_db2' , 表示数据库不存在。
    * Access denied for user 'root'@'localhost' (using password: YES)  , 账号和密码不匹配

6.3 Connection提供的不同的操作对象

3.1 操作对象
        * Statement , 语句执行者,获得方式 conn.createStatement()【】
        * PreparedStatement , 预处理对象,获得方法  conn.prepareStatement(sql)【】
        * 必须先提供sql语句,进行预先处理。
        * CallableStatement 存储过程,  prepareCall(String sql),将sql语句编写数据库,相当于数据库函数,执行时    只需要传递实际参数
3.2 Statement
    int executeUpdate(sql) 执行DDL/DML语句,返回影响的行数。【】
    ResultSet  executeQuery(sql) 执行DQL语句,返回结果集(相当于一个表)【】
    boolean execute(sql) 
        返回值true,表示执行DQL语句,必须通过  getResultSet() 获得结果集
        返回值false,表示执行DML/DDL语句,必须通过  getUpdateCount() 获得影响行数 
3.3 滚动结果集 (了解)
    * jdbc规范 默认结果集forward ,只能向前的结果集。
    * 滚动结果集:可以向前,也可以向后。mysql 直接支持滚动
    * ResultSet api
        next() 下一个(向前)
        previous() 上一个(向后)
    * 结果集ResultSet要滚动,前提Statement必须设置支持的。 
    * 使用方法:createStatement(int resultSetType, int resultSetConcurrency)
        resultSetType - 结果集类型,
                ResultSet.TYPE_FORWARD_ONLY,仅仅只能向前
                ResultSet.TYPE_SCROLL_INSENSITIVE,可以滚动,不敏感。滚动中,数据库发生改变,结果集内容不改变的。
                    数据库的数据是否同步到结果集ResultSet中。
                ResultSet.TYPE_SCROLL_SENSITIVE,可以滚动,敏感。滚动中,数据库数据发生改变,结果集内容改变。
        resultSetConcurrency - 并发类型
            ResultSet.CONCUR_READ_ONLY ,结果集只能读,不能改。
            ResultSet.CONCUR_UPDATABLE,结果集可以更新,数据一并更改。
                结果集数据同步到数据库
    * 操作
        获得  getXxx(int)获得指定列号的内容,  getXxx(String)获得指定列名(字段)的内容
        例如:getString(4) 获得第4列,  getString("username")  获得字段名称username的值

7.SQL注入

sql注入 :用户输入实际参数,作为了sql语句语法的一部分,数据库编译在执行时生效的。
select * from t_user where username = ‘jack’ or 1=1 or 1=’’ and password = ‘12345’
select * from t_user where username = ‘jack’ –’ and password = ‘12345’
解决方案:
1. 手动方式:\转义单引号
2. 使用预处理对象,防止sql注入
1) 先提供sql语句,将实际参数使用占位符?替换。
例如:select * from t_user where username = ? and password = ?
2) 获得预处理对象,获得对象时必须提供sql语句,让sql语句预先进行编译。
3) 设置实际参数
PreparedStatement 提供 setXxx(int , Object)
参数1:int表示 ?位置,从1开始。
参数2:Object具体类型,如果字符串String等。
3. PreparedStatement 接口 是 Statement接口的子接口。
但是execute(sql) 父类方法,子类使用抛异常。使用的没有参数。

8.预处理对象PreparedStatement

特点:
    sql 易于编写,更佳清晰
    提高性能,编译一次,可以执行多次。
编写步骤:
    1.提供sql语句,并将实际参数使用?占位符
    2.获得预处理对象,注意提供sql语句
    3.设置实际参数,将?替换回来
    4.执行,注意:不能设置sql语句。
Statement  和 PreparedStatement  对比:
    一般情况使用PreparedStatement,之后学习框架DbUtils底层使用PreparedStatement,hibernate底层使用也是。
    如果使用Statement,必须保证sql都是自己编写,实际参数都是自己传递的。
PreparedStatement 应用场景
    1.防sql注入
    2.大数据
        大数据类型:blob 字节 、text 字符
    3.批处理

MySql笔记

1.数据库知识

分类:

  1. 网状型数据库
  2. 层次型数据库
  3. 关系型数据库
    • Oracle : 甲骨文,oracle公司,大型数据,收费
    • db2 : IBM,大型数据,收费
    • Sql server : 微软,中性数据,收费。(access office 小型)
    • Mysql : 免费。小型。(开源) –oracle

2.Mysql安装

  1. 设置数据库存放目录
    QQ截图20160630165126.png

  2. 选择配置类型 QQ截图20160630165743.png

  3. 选择服务类型 QQ截图20160630165834.png

  4. 选择数据库类型 QQ截图20160630165920.png

  5. 设置并发连接数 QQ截图20160630170001.png

  6. 配置网络参数 QQ截图20160630170103.png

  7. 设置字符集 QQ截图20160630170134.png

  8. 设置服务和环境静变量 QQ截图20160630170302.png

  9. 设置数据库密码 QQ截图20160630170328.png

  10. 测试

    C:\Users\xxxxx>mysql --version
    mysql  Ver 14.14 Distrib 5.5.27, for Win64 (x86)

3.Mysql登录&修改数据库密码

mysql -h 主机(ip地址) -u 账号 -p 密码

use mysql;
update user set password=password('1234') where user='root';

4.常用命令

  • 显示当前数据库服务器中的数据库列表 : show databases;
  • 使用数据库 : use 数据库名;
  • 显示数据库中的数据表 : show tables;
  • 显示当前所使用的数据库名称 : select database();
  • 显示当前数据库的状态 : status;
  • 显示某个表的表结构 : desc 表名;
  • 显示所有支持的字符集 : show character set;
  • 查看创建表的sql语句 : show create table 表名;

5.SQL语句

5.1 DDL数据定义语言(了解)

> 操作数据库或表结构

5.1.1 数据库操作

  • 创建数据库 : create database 数据库名称;
  • 查询数据库创建语句 : show create database 数据库名称;
  • 删除数据库 : drop database [if exists] 数据库名称;
  • 修改数据 : alter database 数据库名 character set 字符集 collate 比较方式不建议修改。

5.1.2 表结构

> 操作表之前,必须先切换数据库.
  • 创建表 : create table 表名(字段描述,字段描述,...);

    create table users(
        id varchar(32),
        name varchar(50),
        age int
    );
  • 删除表 : drop table 表名;

  • 修改字段类型 : alter table 表名 modify 字段名称 新类型;

  • 修改字段名称 : alter table 表名 change 旧字段 新字段 新字段类型;

  • 添加字段 : alter table 表名 add column 字段名称 字段类型;

  • 删除字段 : alter table 表名 drop column 字段名称;

  • 重命名表名 : alter table 表名 rename [to] 新表明;

5.1.3 数据类型

字符串

char(n) 固定字符串,例如:char(5) 表示可以存放5个字符,且必须是5个。
    如果插入 “abc”,结果“abc  ”  右边自动添加空格。
varchar(n) 可变长字符串,例如:varchar(5),表示最多存放5个字符,如果不够就原样存放。
    如果插入“abc”,结果“abc”

数字

bit            比特
tinyint        byte
mediumint    short
int            int        【】
bigint        long
float            float
double(m,d)    double 【】 --m数字长度,d精度及小数位
numeric        Number    所有数字
    例如:double(5,2) 5表示整个数字为5位,2表示小数位2个。最大值。999.99

时间日期

** 之后使用java日期时间类型:java.util.Date 。如果要使用java.sql..类型,只能存放dao层
date 日期                java.sql.Date
datetime 日期时间            ---
time 时间                java.sql.Time
timestamp 时间戳            java.sql.Timestamp

    sql转util : java.util.Date date = new java.sql.Date(long);
    util转sql : new java.sql.Date(  new java.util.Date().getTime()  )

大数据

字节:存放二进制  (java.sql.Blob :Binary Large Object 二进制大对象)
    TINYBLOB  255
    blob        64k
    longblob    4G
字符:存放文本 (java.sql.Clob :Character Large Object 字符大对象)
    TINYTEXT    255
    text        64k
    longtext 4G

5.2 DML数据操作语言(掌握)

> 对表中的数据进行增删改的操作

5.2.1 插入数据

insert into 表名(字段列表) values(字段对应值);

注意:

多个字段之间使用逗号分隔
字段值必须使用引号(建议单引号),如果是整形数据引号可以省略
字段默认值为null

5.2.2 更新数据

update 表名 set 字段名=字段值,字段名=字段值,...;
update 表名 set 字段名=字段值,字段名=字段值,...where 条件;

5.2.3 删除数据

delete from 表名 [where 条件];

注意:

delete from users; 删除表中的所有数据.进行删除操作留心,一般情况应用系统不进行数据删除,提供一个标记字段,逻辑删除(0表示已删除,1表示没有删除).

5.3 约束

给字段添加规则,约定内容编写。最终作用保证数据的完整性,一致性等。

5.3.1 主键约束

关键字:primary key
要求:数据唯一,不能为null.

1.定义表:声明字段时,定义主键.(primary key)只能修饰一个字段.
create table pk01(
id varchar(32) primary key ,
content varchar(50)
);
2.定义表,声明字段之后,在约束区域定义主键。—特点 constraint primary key (字段1,字段2,….) 可以设置多个字段
create table pk02(
id varchar(32),
content varchar(50),
constraint primary key (id)
);
3.定义表,声明字段,表创建之后。修改表结构添加约束。–特点:也可以设置多个字段,更灵活。
create table pk03(
id varchar(32),
content varchar(50)
);
alter table pk03 add constraint primary key (id);

5.3.2 唯一约束

关键字:unique
要求:被修饰的字段不能重复

1.定义表,声明字段时,定义唯一约束。— 特点:unique只能修饰一个字段
create table un01(
id varchar(32),
content varchar(50) unique
);
2.定义表,声明字段之后,在约束区域定义唯一约束。—特点 constraintunique (字段1,字段2,….) 可以设置多个字段
create table un02(
id varchar(32),
content varchar(50),
constraint unique (content)
);
3.定义表,声明字段,表创建之后。修改表结构添加唯一约束。–特点:也可以设置多个字段,更灵活。
create table un03(
id varchar(32),
content varchar(50)
);
alter table un03 add constraint unique (content);

5.3.3 非空约束

关键字:not null
要求:被修饰的字段不能为null

1.定义表,声明字段时,添加约束。
create table nn01(
id varchar(32),
content varchar(50) not null
);
create table nn02(
id varchar(32),
content varchar(50) not null default ‘dzd’
);

总结: 主键 = 唯一 + 非空

5.3.4 自动增长(mysql特有)

定义:
关键字:auto_increment
mysql特有的一个特殊的关键字,被修饰的字段将自动的累加(oracle没有,但提供徐磊sequence)
注意:
1.字段类型必须是整型,一般使用int
2.必须是key(主键/唯一),一般使用主键primary key
3.被auto_increment修饰的字段,不需要手动维护数据,mysql将自动维护
代码示例:
create table ai01(
id varchar(32) auto_increment, # 错误代码 不能用于字符串
content varchar(50)
);
create table ai02(
id int auto_increment, # 错误代码 必须是primary key
content varchar(50)
);
create table ai03(
id int primary key auto_increment, # 正确代码
content varchar(50)
);
面试题:
drop table ai03; #删除表,数据和表都不存在了。
delete from ai03; #删除所有数据,表仍然存在。表中计数器没有重置。
truncate table ai03; #清空所有数据,表中的计数器将重置归0。
delete 和 truncate 对比
delete 将数据删除了
truncate 先删除了表,再创建表。

5.3.5 外键约束

关键字:foreign key

5.3.6 删除约束

删除主键:mysql>   `alter table 表名 drop primary key;`
删除唯一:修改列
删除外键:mysql>   `alter table 表名 drop foreign key 名称;`

5.3.7 cmd命令行中文乱码处理

set names gbk;

5.4 DQL数据查询语言(掌握)

5.4.1 无条件查询

查询所有:

select * from users;
select id,name,age from user;

查询部分字段:

select id,name from user;

合并查询条件:

select id,concat(firstname,secondname),age from users;

字段别名:

select id,concat(firstname,secondname) as `姓名`,age from users;

特殊字符或者关键字使用重音符 ``

5.4.2 带条件查询

查询分数等于60的:

select * from users where count='60';

查询年龄大于18的学生:

select * from users where age > 18;

查询分数在60-80之间:

select * from users where count >= 60 and count <= 80;
select * from users where count between 60 and 80;

查询年龄是18或20的学生:

select * from users where age = 18 or age = 20;

模糊查询,不完全匹配:

字段:like
符号:    
    %匹配多个数据
        '云' 只能匹配一个云
        '%云' 匹配以云结尾的
        '云%' 匹配以云开头的
        '%云%' 包含云
    _匹配一个数据

查询分数等于60 或者 分数大于90并且年龄大于23

select * from users where count = 60 or count > 90 and age > 23;
select * from users where count = 60 or (count > 90 and age > 23);
### 运算符优先级  and 优先 or

查询没有考试的学生

select * from users where count is null;

查询所有考试的学生

select * from users where count is not null;

运算符 不相等 != <>

5.4.3 聚合函数

聚合函数:对表中的数据进行统计,显示一个数据(一行一列的数据)

聚合函数不统计 null值。

有多少条记录 count(* | 字段)

select count(*) from users;
select count(id) from users;    #7
select count(count) from users;    #6

平均成绩 avg

select avg(count) from users;    #不精准(没有null)
select sum(count)/count(id) from users; #精准(计算null)

最高成绩 max

select max(count) from users;

最小年龄 min

select min(age) from users;

班级总成绩 sum

select sum(count) from users;

查询所有的年龄数(排序)

去重复 distinct
排序 select..... order by 字段1 关键字, 字段2 关键字,....
### 关键字 asc 升序 , desc 降序
select distinct age from users order by age desc;   # age asc 等效 age [asc] 

5.4.4 分组查询

添加班级字段(classes)

alter table users add column classes varchar(3);
update users set classes = 1;
update users set classes = 2 where id='u005' or id ='u006' or id ='u007';
update users set classes = 2 where id in ('u005','u006','u007');

查询1班和2班的平均成绩

分组  select ... group by 分组字段;
select classes,avg(count) from users group by classes;
select classes,sum(count)/count(id) from users group by classes;

查询班级,平均成绩不及格的,班级成员信息

(查询2班,成员信息)
select * from users where classes = 2;

多表操作

select * from A,B where A.classes = B.classes and avg < 60;

表的别名

select ... from 表名 [as] 别名

子查询,一条select语句,作为另一个select一部分。

select * from users,(
select classes,sum(count)/count(id) as cavg from users group by classes) as B
where users.classes = B.classes and cavg < 60;

子查询特点

#查询结果一行一列,可以使用
    select id,(xxx) from
    select ... from ... where id= (xxxx)
#查询结果一行多列(查询多个值),使用关键字 in ,all 等
#查询结果多行多列,可以当另一个表使用