第二十九天-加强1-Junit&类加载&反射&Properties&BeanUtils&xml&动态代理&数据库【悟空教程】

第二十九天-加强1-Junit&类加载&反射&Properties&BeanUtils&xml&动态代理&数据库【悟空教程】

第1天Junit&反射&Properties

第1章 Junit单元测试

1.1 Junit介绍

Junit是Java语言编写单元测试框架,最直观的理解,就是取代java类中的main方法。Junit属于第三方工具,一般情况下需要导入jar包,而多数Java开发环境都集成了Junit。

1.2 Junit的使用

创建“MyJunit”java项目,并创建“cn.com.javahelp_00_Junit”包

1. 编写测试类,简单理解Junit可以用于取代java的main方法

2. 在测试类方法上添加注解 @Test

3. @Test修饰的方法要求:public void 方法名() {…} ,方法名自定义建议test开头,没有参数。

4. 添加Eclipse中集成的Junit库,鼠标点击“@Test”,使用快捷键“ctrl + 1”,点击“Add Junit …”

结果

5. 使用:选中方法右键,执行当前方法;选中类名右键,执行类中所有方法(方法必须标记@Test)

6. 常用注解

@Test,用于修饰需要执行的方法

@Before,测试方法前执行的方法

@After,测试方法后执行的方法

7. 常见使用错误,如果没有添加“@Test”,使用“Junit Test”进行运行,将抛异常

第2章 Java类加载机制

2.1 概述

class文件由类加载器装载后,在JVM中将形成一份描述class结构的元信息对象,通过该元信息对象Class可以获知class文件的结构信息:如构造函数,属性和方法等。

虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

简而言之:class文件被虚拟机加载在内存生产Class对象。

2.2 工作机制

类加载器就是寻找类的字节码文件,并构造出类在JVM内部表示的对象组件。在Java中,类加载器把一个类装入JVM中,要经过以下步骤:

1、 加载:查找和导入class文件;

2、 链接:把类的二进制数据合并到JRE中;

  • 校验:检查载入Class文件数据的正确性;
  • 准备:给类的静态变量分配存储空间;
  • 解析:将符号引用转成直接引用;

3、 初始化:对类的静态变量,静态代码块执行初始化操作

  • 加载:

在装载阶段,虚拟机需要完成以下3件事情

  • 通过一个类的全限定名来获取定义此类的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
  • 在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。

虚拟机规范中并没有准确说明二进制字节流应该从哪里获取以及怎样获取,这里可以通过定义自己的类加载器去控制字节流的获取方式。

  • 校验:

虚拟机如果不检查输入的字节流,对其完全信任的话,很可能会因为载入了有害的字节流而导致系统奔溃。

  • 准备:

准备阶段是正式为类变量分配并设置类变量初始值的阶段,这些内存都将在方法区中进行分配,需要说明的是:

这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中;这里所说的初始值“通常情况”是数据类型的零值,假如:

public static int value = 123;

value在准备阶段过后的初始值为0而不是123,而把value赋值的putstatic指令将在初始化阶段才会被执行

2.3 类初始化的时机

下列四种情况能够触发类的初始化

  • 使用new关键字实例化对象的时候,读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。
  • 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
  • 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
  • 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

第3章 反射

3.1 反射概述

Java反射机制是在运行状态中,对指定的类,任意的方法或任意的字段进行操作,这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。

简而言之,反射就是:在运行时通过代码操作类。

想要操作类,就必须先获得该类的字节码对象Class。通过Class提供的方法对类进行进一步的解剖,从而实现各种操作。

在进行具体操作之前,大家需要先掌握类各个组成的专业描述

  • Class类
  • Constructor 构造
  • Method 方法
  • Field 字段
  • instance 实例
  • invoke 执行

3.2 准备数据

  • 添加字段

public class Bean {

private String id;

private String className;

  • Bean类提供getter和setter方法

public String getId() {

System.out.println("getId方法执行");

return id;

}

public void setId(String id) {

System.out.println("setId方法执行:" + id);

this.id = id;

}

3.3 Class获得方式

//1 通过类型获得

// 语法:类名.class

// 应用场景:确定类型 等

Class clazz1 = Bean.class;

//2 通过实例对象获得

// 语法:变量.getClass()

// 应用场景:在方法内部通过参数获得类型 等

Bean bean = new Bean();

Class clazz2 = bean.getClass();

//3 通过字符串获得

// 语法:Class.forName("全限定类名")

// 应用场景:通过配置获得字符串 等

Class clazz3 = Class.forName("cn.com.javahelp_00_Bean.Bean");

3.4 构造方法与实例

3.4.1 添加构造

  • 修改Bean ,添加构造方法

3.4.2 无参构造

  • 无参构造,并获得实例

3.4.3 有参构造

  • 有参构造,并获得实例

3.4.4 无参构造,简化版获得实例

  • 无参构造,简化版获得实例

3.4.5 扩展:私有构造(暴力反射)

  • 修改Bean添加私有构造
  • getConstructor() 使用该方法将无法获得私有方法,程序运行抛异常
  • 没有使用setAccessible(true),将抛异常

3.5 方法与执行

3.5.1 public方法

  • 获得方法并设置

3.5.2 扩展:私有方法(暴力反射)

  • 修改bean,添加方法:

//私有方法

private String show(){

System.out.println("私有方法执行");

return "Bean["+id+", "+ className +"]";

}

  • getMethod() 使用该方法将无法获得私有方法,程序运行抛异常
  • 没有使用setAccessible(true),将抛异常

3.5.3 扩展:main方法与执行

  • 修改Bean,添加main方法

public static void main(String[] args) {

for (int i = 0; i < args.length; i++) {

System.out.print(args[i] +", ");

}

}

  • 通过反射,调用执行main方法

3.6 字段(成员变量)与数据操作(了解)

3.6.1 添加public字段

  • Bean类提供成员变量 address

public class Bean {

private String id;

private String className;

public String description;

3.6.2 public字段的操作

3.6.3 扩展:私有字段(暴力反射)

  • getField() 使用该方法将无法获得私有字段,程序运行抛异常
  • 没有使用setAccessible(true),将抛异常

第4章 Properties

4.1 Properties类概述

Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

特点:

1、Map接口的子类,map中的方法都可以用。

2、该集合没有泛型。键值都是字符串。

3、它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备(硬盘、U盘、光盘)上。键值的来源也可以是持久化的设备。

4、有和流技术相结合的方法。

4.2 常用方法

  • public Object setProperty(String key, String value)调用 Map 的方法 put。
  • public Set<String> stringPropertyNames()返回此属性列表中的键集,
  • public String getProperty(String key)用指定的键在此属性列表中搜索属性

代码演示:

4.3 将集合中内容存储到文件

  • store(OutputStream,commonts)
  • store(Writer,comments);

把集合中的数据,保存到指定的流所对应的文件中,参数commonts代表对描述信息

需求:使用Properties集合,完成把集合内容存储到IO流所对应文件中的操作

4.4 读取文件中的数据,并保存到集合

  • load(InputStream)
  • load(Reader)

把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中

需求:从属性集文件prop.properties 中取出数据,保存到集合中

注意:使用字符流FileReader就可以完成文件中的中文读取操作了

第5章 综合案例

5.1 需求

通过配置文件确定创建那个JavaBean对象的实例,并通过配置文件确定JavaBean实例中存放具体数据。

5.2 分析

  • bean.properties 用于配置创建那个JavaBean,此时数据都为默认值。
  • data.properties 用于配置JavaBean存放的具体数据
  • BeanConfig用于封装两个Properties文件中的配置的所有数据

5.3 实现

5.3.1 创建测试JavaBean

  • 创建JavaBean User

public class User {

private String uid;

private String username;

private String password;

  • 创建JavaBean Book

public class Book {

private String bid;

private String title;

private String price;

5.3.2 创建配置文件

  • bean.properties 配置User ,id项暂时没用

id=xxx

className=cn.com.javahelp.domain.User

  • data.properties 配置User对象中具体封装的数据

uid=u001

username=jack

password=1234

5.3.3 创建BeanConfig

  • BeanConfig对象将封装properties文件中配置的所有内容。

public class BeanConfig {

private String id;

private String className;

private Properties props = new Properties();

  • 使用BeanConfig存取数据

5.3.4 实现:解析Properties

@Test

public void demo01() throws Exception{

//解析properties

BeanConfig beanConfig = new BeanConfig();

// bean解析

//1 解析bean.properties文件

//1.1 加载配置文件

Properties beanProps = new Properties();

beanProps.load(new InputStreamReader(new FileInputStream("bean.properties"), "UTF-8"));

//1.2 获得具体数据

String id = beanProps.getProperty("id");

String className = beanProps.getProperty("className");

//1.3将数据封装到BeanConfig

beanConfig.setId(id);

beanConfig.setClassName(className);

// data解析

//2 解析data.properties文件

//2.1 加载配置文件

Properties dataProps = new Properties();

dataProps.load(new InputStreamReader(new FileInputStream("data.properties"), "UTF-8"));

//2.2 将所有的数据存放到Properties对象中

for(String name : dataProps.stringPropertyNames()){

String value = dataProps.getProperty(name);

beanConfig.getProps().setProperty(name, value);

}

System.out.println(beanConfig);

}

5.3.5 实现:使用BeanConfig数据实例对象

@Test

public void demo02() throws Exception{

//模拟数据

BeanConfig beanConfig = new BeanConfig();

beanConfig.setId("xxx");

beanConfig.setClassName("cn.com.javahelp_02_demo.bean.User");

beanConfig.getProps().setProperty("uid", "u001");

beanConfig.getProps().setProperty("username", "jack");

beanConfig.getProps().setProperty("password", "1234");

//从beanConfig获得数据,然后创建对应JavaBean,并赋值

//1 获得需要创建的JavaBean字符串

String className = beanConfig.getClassName();

//2 字节码对象

Class clazz = Class.forName(className);

//3获得实例

Object obj = clazz.newInstance();

//4 执行字段对应setter方法进行赋值操作

for(String name : beanConfig.getProps().stringPropertyNames()){

String value = beanConfig.getProps().getProperty(name);

//执行setter方法,uid --> setUid

// 4.1 获得方法名称

String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);

// 4.2 获得方法

Method method = clazz.getMethod(methodName, String.class);

// 4.3 执行方法

method.invoke(obj, value);

}

System.out.println(obj);

}

5.3.6 实现:整合

  • 将1.3.4抽取成getBean()方法

private BeanConfig getBean() throws Exception{

BeanConfig beanConfig = new BeanConfig();

// bean解析

//1 解析bean.properties文件

//1.1 加载配置文件

Properties beanProps = new Properties();

beanProps.load(new InputStreamReader(new FileInputStream("bean.properties"), "UTF-8"));

//1.2 获得具体数据

String id = beanProps.getProperty("id");

String className = beanProps.getProperty("className");

//1.3将数据封装到BeanConfig

beanConfig.setId(id);

beanConfig.setClassName(className);

// data解析

//2 解析data.properties文件

//2.1 加载配置文件

Properties dataProps = new Properties();

dataProps.load(new InputStreamReader(new FileInputStream("data.properties"), "UTF-8"));

//2.2 将所有的数据存放到Properties对象中

for(String name : dataProps.stringPropertyNames()){

String value = dataProps.getProperty(name);

beanConfig.getProps().setProperty(name, value);

}

return beanConfig;

}

  • 将1.3.5 BeanConfig模拟数据修改成真实数据

第2天BeanUtils&XML入门&Dom4j解析

第6章 BeanUtils工具类

6.1 概述

BeanUtils 是 Apache commons组件的成员之一,主要用于简化JavaBean封装数据的操作。它可以给JavaBean封装一个字符串数据,也可以将一个表单提交的所有数据封装到JavaBean中。

6.2 常用API

使用第三方工具,需要导入jar包:

BeanUtils工具常用工具类:BeanUtils,BeanUtils用于封装数据,常用API如下

方法

描述

BeanUtils对象

populate(Object bean, Map<String,String[]> properties)

将Map数据封装到指定Javabean中,一般用于将表单的所有数据封装到javabean

setProperty(Object obj,String name,Object value)

设置属性值,如果指定属性不存在,不抛异常

getProperty(Object obj,String name)

获得属性值,如果指定属性不存在,抛方法找不到异常

6.3 基本使用

  • 提供JavaBean User ,并提供对应的构造方法
  • 功能1:设置属性
  • 功能2:获得属性

6.4 Populate自动填充

  • 功能3:一次性处理一组数据,数据来自Map

@Test

public void demo03() throws Exception{

Map<String, String[]> map = new HashMap<>();

map.put("id", new String[]{"u001"});

map.put("username", new String[]{"jack"});

map.put("pwd", new String[]{"1234"});

//将数据封装到javabean中

User user = new User();

BeanUtils.populate(user, map);

System.out.println(user);

/* 结果:

* User [id=u001, username=jack, pwd=1234]

*/

}

6.5 自定义工具类

  • 功能3:编写工具类

public class MyBeanUtils {

/**

* 将数据封装给JavaBean,支持时间类型转换

* @param user

* @param properties

*/

public static void populate0(Object user, Map<String,String[]> properties){

try {

// 封装数据

BeanUtils.populate(user, properties);

} catch (Exception e) {

throw new RuntimeException(e);

}

}

/**

* 高级封装,不需要new javabean

* @param beanClass

* @param properties

* @return

*/

public static Object populate1(Class beanClass, Map<String,String[]> properties){

try {

//1 使用反射创建实例

Object bean = beanClass.newInstance();

//3 封装数据

BeanUtils.populate(bean, properties);

return bean;

} catch (Exception e) {

throw new RuntimeException(e);

}

}

}

  • 使用

6.6 扩展:高级

  • 使用

第7章 xml基本使用

7.1 XML概述

7.1.1 什么是XML

XML全称为Extensible Markup Language,意思是可扩展的标记语言。

W3C在1998年2月发布1.0版本,2004年2月又发布1.1版本,但因为1.1版本不能向下兼容1.0版本,所以1.1没有人用。同时,在2004年2月W3C又发布了1.0版本的第三版。我们要学习的还是1.0版本!!!

标记,就是标签。例如:<a></a>

7.1.2 XML的作用

  • 存放数据

<?xml version="1.0" encoding="UTF-8"?>

<persons>

<person id="p001">

<name>张三</name>

</person>

<person id="p002">

<name>李四</name>

</person>

</persons>

类似于java代码

class Person{

String id;

String name;

}

@Test

public void test(){

HashSet<Person> persons = new HashSet<Person>();

persons.add( new Person("p001","张三") );

persons.add( new Person("p002","李四") );

}

  • 配置文件

<?xml version="1.0" encoding="UTF-8"?>

<beans>

<bean id="user1" className="cn.com.javahelp_00_Bean.User">

<property name="id" value="u001"></property>

<property name="username" value="jack"></property>

<property name="pwd" value="1234"></property>

</bean>

<bean id="user2" className=" cn.com.javahelp_00_Bean.User">

<property name="id" value="u002"></property>

<property name="username" value="rose"></property>

<property name="pwd" value="5678"></property>

</bean>

</beans>

类似于java代码

class Bean{

private String id;

private String className;

private Properties prop;

//补全set\get方法

}

@Test

public void test(){

HashSet<Bean> beans = new HashSet<Bean>();

Bean b1 = new Bean();

b1.setId("user1");

b1.setClassName("cn.com.javahelp.domain.User");

Properties prop = new Properties();

prop.setProperties("id","u001");

prop.setProperties("username","jack");

prop.setProperties("pwd","1234");

b1.setProp( prop );

Bean b2 = new Bean();

b2.setId("user2");

b2.setClassName("cn.com.javahelp.domain.User");

Properties prop = new Properties();

prop.setProperties("id","u002");

prop.setProperties("username","rose");

prop.setProperties("pwd","5678");

b2.setProp( prop );

beans.add(b1);

beans.add(b2);

}

7.2 XML的语法

7.2.1 XML 文件

  • Xml文件扩展名必须为xml
  • Xml内容必须满足以下要求
    • 固定的文档声明
    • 合格的元素和属性
    • 正确的注释
    • 符合要求的特殊字符编写规则

7.2.2 文档声明

  • XML文档声明格式:

<?xml version="1.0" encoding="UTF-8"?>

1. 文档声明必须为<?xml开头,以?>结束;

2. 文档声明必须从文档的0行0列位置开始;

3. 文档声明只有2个属性:

a) versioin:指定XML文档版本。必须属性,因为我们不会选择1.1,只会选择1.0;

b) encoding:指定当前文档的编码。可选属性,常用值是utf-8;

7.2.3 元素

  • 元素 element

<bean></bean>

1. 元素是XML文档中最重要的组成部分,

2. 普通元素的结构开始标签、元素体、结束标签组成。例如:<hello>大家好</hello>

3. 元素体:元素体可以是元素,也可以是文本,例如:<b><a>你好</a></b>

4. 空元素:空元素只有开始标签,而没有结束标签,但元素必须自己闭合,例如:<c/>

5. 元素命名:

a) 区分大小写

b) 不能使用空格,不能使用冒号:

c) 不建议以XML、xml、Xml开头

6. 格式化良好的XML文档,必须只有一个根元素。

7.2.4 属性

  • 属性attribute

<bean id=”” className=””>

1. 属性是元素的一部分,它必须出现在元素的开始标签中

2. 属性的定义格式:属性名=属性值,其中属性值必须使用单引或双引

3. 一个元素可以有0~N个属性,但一个元素中不能出现同名属性

4. 属性名不能使用空格、冒号等特殊字符,且必须以字母开头

7.2.5 注释

XML的注释,以“<!--”开始,以“-->”结束。注释内容会被XML解析器忽略!

7.2.6 转义字符

  • 转义字符

因为很多符号已经被XML文档结构所使用,所以在元素体或属性值中想使用这些符号就必须使用转义字符,例如:“<”、“>”、“’”、“””、“&”。

7.2.7 CDATA

  • CDATA区

<![CDATA[

任意内容

]]>

当大量的转义字符出现在xml文档中时,会使xml文档的可读性大幅度降低。这时如果使用CDATA段就会好一些。

在CDATA段中出现的“<”、“>”、“””、“’”、“&”,都无需使用转义字符。这可以提高xml文档的可读性。

在CDATA段中不能包含“]]>”,即CDATA段的结束定界符。

7.3 XML约束

在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束。

常见的xml约束:DTD、Schema

目的:通过约束文档,可以编写出xml文档(具有固定格式,规定的格式)。

7.3.1 DTD约束

7.3.1.1 什么是DTD

DTD(Document Type Definition),文档类型定义,用来约束XML文档。规定XML文档中元素的名称,子元素的名称及顺序,元素的属性等。

7.3.1.2 DTD重点要求

开发中,我们很少自己编写DTD约束文档,通常情况我们都是通过框架提供的DTD约束文档,编写对应的XML文档。常见框架使用DTD约束有:struts2、hibernate等。

通过提供的DTD“bean.dtd”编写XML

<?xml version="1.0" encoding="UTF-8"?>

<!--

DTD教学实例文档。

模拟spring规范,如果开发人员需要在xml使用当前DTD约束,必须包括DOCTYPE。

格式如下:

<!DOCTYPE beans SYSTEM "bean.dtd">

-->

<!ELEMENT beans (bean*,import*) >

<!ELEMENT bean (property*)>

<!ELEMENT property (#PCDATA)>

<!ELEMENT import (#PCDATA)>

<!ATTLIST bean id CDATA #REQUIRED

className CDATA #REQUIRED

>

<!ATTLIST property name CDATA #REQUIRED

value CDATA #REQUIRED

>

<!ATTLIST import resource CDATA #REQUIRED>

7.3.1.3 案例实现

  • 步骤1:创建bean-dtd.xml文档,并将“bean.dtd”拷贝相同目录下。
  • 步骤2:从DTD文档开始处,拷贝需要的“文档声明”
  • 步骤3:完成xml内容编写
    • 需要掌握基本符号
      • , 表示两个元素之间关系,为顺序
      • | 表示两个元素之间关系,为选中
      • * 表示当前修饰出现次数,为任意
      • + 表示当前修饰出现次数,为至少有一个(>=0)
      • ? 表示当前修饰出现次数,为0或1

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans SYSTEM "bean.dtd">

<beans>

<bean id="" className=""></bean>

<bean id="" className="">

<property name="" value=""></property>

<property name="" value=""></property>

</bean>

<import resource=""></import>

<import resource=""></import>

</beans>

7.3.1.4 DTD语法(了解)

7.3.1.4.1 文档声明

1. 内部DTD,在XML文档内部嵌入DTD,只对当前XML有效。

<?xml version="1.0" encoding="utf-8" ?>

<!DOCTYPE beans [

... //具体的语法

]>

<beans>

</beans>

2. 外部DTD—本地DTD,DTD文档在本地系统上,公司内部自己项目使用。

<?xml version="1.0" encoding="utf-8" ?>

<!DOCTYPE beans SYSTEM "bean.dtd">

<beans>

</beans>

3. 外部DTD—公共DTD,DTD文档在网络上,一般都有框架提供。

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"

"http://www.springframework.org/dtd/spring-beans-2.0.dtd">

<beans>

</beans>

7.3.1.4.2 元素声明

定义元素语法:<!ELEMENT 元素名 元素描述>

元素名:自定义

元素描述包括:符号和数据类型

常见符号:? * + () | ,

常见类型:#PCDATA 表示内容是文本,不能是子标签

  • 实例
7.3.1.4.3 属性声明

属性的语法:(attribute)

<!ATTLIST 元素名

属性名 属性类型 约束

属性名 属性类型 约束

...

>

元素名:属性必须是给元素添加,所有必须先确定元素名

属性名:自定义

属性类型:ID、CDATA、枚举 …

ID : ID类型的属性用来标识元素的唯一性

CDATA:文本类型

枚举:(e1 | e2 | ...) 多选一

约束:

#REQUIRED:说明属性是必须的;required

#IMPLIED:说明属性是可选的;implied

  • 实例

7.3.2 Schema约束

7.3.2.1 什么是Schema

Schema是新的XML文档约束;

Schema要比DTD强大很多,是DTD 替代者;

Schema本身也是XML文档,但Schema文档的扩展名为xsd,而不是xml。

Schema 功能更强大,数据类型更完善

Schema 支持名称空间

7.3.2.2 Schema重点要求

与DTD一样,要求可以通过schema约束文档编写xml文档。常见框架使用schema的有:Spring等

通过提供“bean-schema.xsd”编写xml文档

<?xml version="1.0" encoding="UTF-8"?>

<!--

Schema教学实例文档。

模拟spring规范,如果开发人员需要在xml使用当前Schema约束,必须包括指定命名空间。

格式如下:

<beans xmlns="http://www.javahelp.com.cn/bean"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.javahelp.com.cn/bean bean-schema.xsd"

>

-->

<schema xmlns="http://www.w3.org/2001/XMLSchema"

targetNamespace="http://www.javahelp.com.cn/bean"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:tns="http://www.javahelp.com.cn/bean"

elementFormDefault="qualified">

<!-- 声明根标签 -->

<element name="beans">

<complexType>

<choice minOccurs="0" maxOccurs="unbounded">

<element name="bean">

<complexType>

<sequence minOccurs="0" maxOccurs="unbounded">

<element name="property">

<complexType>

<attribute name="name" use="required"></attribute>

<attribute name="value" use="required"></attribute>

</complexType>

</element>

</sequence>

<attribute name="id" use="required"></attribute>

<attribute name="className" use="required"></attribute>

</complexType>

</element>

<element name="import">

<complexType>

<attribute name="resource" use="required"></attribute>

</complexType>

</element>

</choice>

</complexType>

</element>

</schema>

  • 案例文档中同一个“命名空间”分别使用“默认命名空间”和“显示命名空间”进行引入,所以文档中<schema>和<xsd:schema>作用一样。

7.3.2.3 案例实现

1. 步骤1:创建bean.xml,并将“bean-schema.xsd”拷贝到同级目录

2. 步骤2:从xsd文档中拷贝需要的“命名空间”

3. 完成xml内容编写

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.javahelp.com.cn/bean"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.javahelp.com.cn/bean bean-schema.xsd"

>

<bean id="" className=""></bean>

<bean id="" className="">

<property name="" value=""/>

<property name="" value=""/>

</bean>

<import resource=""/>

<import resource=""/>

</beans>

7.3.2.4 命名空间(语法)

7.3.2.4.1 什么是命名空间

如果一个XML文档中使用多个Schema文件,而这些Schema文件中定义了相同名称的元素时就会出现名字冲突。这就像一个Java文件中使用了import java.util.*和import java.sql.*时,在使用Date类时,那么就不明确Date是哪个包下的Date了。

总之名称空间就是用来处理元素和属性的名称冲突问题,与Java中的包是同一用途。如果每个元素和属性都有自己的名称空间,那么就不会出现名字冲突问题,就像是每个类都有自己所在的包一样,那么类名就不会出现冲突。

7.3.2.4.2 约束文档和XML关系

当W3C提出Schema约束规范时,就提供“官方约束文档”。我们通过官方文档,必须“自定义schema 约束文档”,开发中“自定义文档”由框架编写者提供。我们提供“自定义文档”限定,编写出自己的xml文档。

7.3.2.4.3 声明命名空间

默认命名空间:<xxx xmlns=””> ,使用<标签>

显式命名空间:<xxx xmlns:别名=””> , 使用<别名:标签>

  • 实例:bean.xml
7.3.2.4.4 其他介绍
  • 自定义约束:web-app_2_5.xsd
  • xml文档:web.xml

<beans xmlns="http://www.javahelp.cn/bean"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.javahelp.com.cn/bean bean-schema.xsd"

>

xmlns:xsi=”…” 固定写法

表示是一个schema实例文档,就是被schema文档约束的xml文档。

xsi:schemaLocation=”名称 路径 名称 路径 名称 路径 …”

表示用于确定当前xml文档使用到的schema文档的位置。“名称 路径”是成对出现,与xmlns引用命名空间对应。

  • 综合案例:(了解)

综合案例目的是:一个“命名空间”必须在schemaLocation中有一个成对描述信息(名称 路径)

  • 案例练习1:
  • 案例练习2:

7.4 dom4j解析

7.4.1 XML解析概述

当将数据存储在XML后,我们就希望通过程序获得XML的内容。如果我们使用Java基础所学习的IO知识是可以完成的,不过你需要非常繁琐的操作才可以完成,且开发中会遇到不同问题(只读、读写)。人们为不同问题提供不同的解析方式,并提供对应的解析器,方便开发人员操作XML。

7.4.2 解析方式和解析器

  • 开发中比较常见的解析方式有三种,如下:

1. DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象。

a) 优点:元素与元素之间保留结构关系,故可以进行增删改查操作。

b) 缺点:XML文档过大,可能出现内存溢出显现。

2. SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都将触发对应的事件。(了解)

a) 优点:处理速度快,可以处理大文件

b) 缺点:只能读,逐行后将释放资源。

3. PULL:Android内置的XML解析方式,类似SAX。(了解)

  • 解析器:就是根据不同的解析方式提供的具体实现。有的解析器操作过于繁琐,为了方便开发人员,有提供易于操作的解析开发包。
  • 常见的解析开发包:
    • JAXP:sun公司提供支持DOM和SAX开发包
    • JDom:dom4j兄弟
    • jsoup:一种处理HTML特定解析开发包
    • dom4j:比较常用的解析开发包,hibernate底层采用。

7.4.3 DOM解析原理及结构模型

XML DOM 将 整个XML文档加载到内存,生成一个DOM树,并获得一个Document对象,通过Document对象就可以对DOM进行操作

DOM中的核心概念就是节点,在XML文档中的元素、属性、文本等,在DOM中都是节点!

7.4.4 API使用

如果需要使用dom4j,必须导入jar包。

dom4j 必须使用核心类SaxReader加载xml文档获得Document,通过Document对象获得文档的根元素,然后就可以操作了。

常用API如下:

1. SaxReader对象

a) read(…) 加载执行xml文档

2. Document对象

a) getRootElement() 获得根元素

3. Element对象

a) elements(…) 获得指定名称的所有子元素。可以不指定名称

b) element(…) 获得指定名称第一个子元素。可以不指定名称

c) getName() 获得当前元素的元素名

d) attributeValue(…) 获得指定属性名的属性值

e) elementText(…) 获得指定名称子元素的文本值

f) getText() 获得当前元素的文本内容

@Test

public void demo01() throws Exception

//#1 获得document

SAXReader saxReader = new SAXReader();

Document document = saxReader.read(new File("01.xml/data.xml"));

//#2 获得根元素<beans>

Element rootElement = document.getRootElement();

//#3 获得所有子元素。例如:<bean>

List<Element> allBeanElement = rootElement.elements();

//#4 遍历所有

for (Element beanElement : allBeanElement) {

// #5.1 打印元素名

String childEleName = beanElement.getName();

System.out.println(childEleName);

// #5.2 获得bean的id和className属性

String id = beanElement.attributeValue("id");

String className = beanElement.attributeValue("className");

System.out.print(id + " , ");

System.out.println(className);

//#6 获得所有<property>子元素

List<Element> allPropertyElement = beanElement.elements("property");

for (Element propElement : allPropertyElement) {

String name = propElement.attributeValue("name");

String value = propElement.attributeValue("value");

System.out.print("\t");

System.out.print(name + " , ");

System.out.println(value);

}

}

}

第3天XML案例&注解&类加载器&动态代理

第8章 XML综合案例

8.1 需求

提供一个工厂,可以创建指定的对象。创建的对象通过XML配置确定。

例如:

getBean(“id001”) 将获得 id001对应User实例对象,并为User对象封装了指定的数据。

8.2 分析

我们可以多次调用 BeanFactory.getBean(“beanId”),将创建不同对象。

1. BeanFactory首先加载(解析) xml配置文件

2. 将每一个<bean>标签配置内容,封装到BeanConfig对象中

3. 最后将整个xml所有配置内容都封装一个容器,且此容器可以快速查询。将采用Map进行数据存储。

8.3 实现

8.3.1 测试JavaBean和XML数据

<beans>

<bean id="beanId01" className="cn.com.javahelp.domain.User">

<property name="uid" value="u001"></property>

<property name="username" value="jack"></property>

<property name="pwd" value="1234"></property>

</bean>

<bean id="beanId02" className="cn.com.javahelp.domain.Book">

<property name="bid" value="b001"></property>

<property name="title" value="标题"></property>

<property name="price" value="998"></property>

</bean>

</beans>

8.3.2 BeanConfig对象

public class BeanConfig {

private String id;

private String className;

private Properties props = new Properties();

8.3.3 解析xml将数据封装到BeanConfig对象中

public class BeanFactory {

//1.1 提供Map存放 bean.xml配置文件中所有内容,且易于快速查询,使用Map<String,BeanConfig>

private static Map<String,BeanConfig> cache = new HashMap<String, BeanConfig>();

//1.2 解析xml,将数据添加到map中

static{

try {

//1) 加载xml文件,获得document

SAXReader saxReader = new SAXReader();

Document document = saxReader.read("bean.xml");

//2) 获得根元素<beans>

Element rootElement = document.getRootElement();

//3) 获得所有<bean>元素

List<Element> allBeanElement = rootElement.elements("bean");

for(Element beanElement : allBeanElement) {

//4) 获得id和className属性

String id = beanElement.attributeValue("id");

String className = beanElement.attributeValue("className");

/**#1 创建BeanConfig, 并封装id和className、*/

BeanConfig beanConfig = new BeanConfig();

beanConfig.setId(id);

beanConfig.setClassName(className);

//5) 获得<property>子标签

List<Element> allPropertyElement = beanElement.elements("property");

for(Element propElement : allPropertyElement) {

//6) 获得name和value属性

String name = propElement.attributeValue("name");

String value = propElement.attributeValue("value");

/**#2 将 name和value 封装到 BeanConfig.props中*/

beanConfig.getProps().setProperty(name, value);

}

/**#3 将封装好的BeanConfig,添加到Map中*/

cache.put(id, beanConfig);

}

System.out.println("数据初始化成功:" + cache);

} catch (Exception e) {

//将编译时转换成运行时异常

throw new RuntimeException(e);

}

}

8.3.4 使用BeanConfig对象实例化执行对象

/**

* 通过指定 bean id 获得具体实例对象

* @param beanId

* @return

*/

public static Object getBean(String beanId){

//1 通过beanId 从Map中获得对应BeanConfig

BeanConfig beanConfig = cache.get(beanId);

if(beanConfig == null){

throw new RuntimeException("获得对象["+beanId+"]不存在");

}

try {

//2 通过 beanConfig.className 创建实例对象

String className = beanConfig.getClassName();

Class clazz = Class.forName(className);

Object obj = clazz.newInstance();

//3 循环遍历 BeanConfig.props ,使用BeanUtils进行数据封装

for(String name : beanConfig.getProps().stringPropertyNames()){

String value = beanConfig.getProps().getProperty(name);

//使用BeanUtils封装数据

BeanUtils.setProperty(obj, name, value);

}

return obj;

} catch (Exception e) {

throw new RuntimeException(e);

}

}

8.3.5 测试

@Test

public void demo01(){

User user = (User)BeanFactory.getBean("id001");

System.out.println(user);

Book book = (Book)BeanFactory.getBean("id002");

System.out.println(book);

}

第9章 注解

9.1 注解概述

  • 什么是注解:Annotation注解,是一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次
    • 对比注释:注释是给开发人员阅读的,注解是给计算机提供相应信息的。
  • 注解的作用:

1. 编译检查:通过代码里标识注解,让编译器能够实现基本的编译检查。例如:@Override

2. 代码分析:通过代码里标识注解,对代码进行分析,从而达到取代xml目的。

3. 编写文档:通过代码里标识注解,辅助生成帮助文档对应的内容

9.2 JDK提供的注解

1. @Deprecated 表示被修饰的方法已经过时。过时的方法不建议使用,但仍可以使用。

  • 一般被标记位过时的方法都存在不同的缺陷:1安全问题;2新的API取代

2. @Override JDK5.0表示复写父类的方法;jdk6.0 还可以表示实现接口的方法

3. @SuppressWarnings 表示抑制警告,被修饰的类或方法如果存在编译警告,将被编译器忽略

deprecation ,或略过时

rawtypes ,忽略类型安全

unused , 忽略不使用

unchecked ,忽略安全检查

null,忽略空指针

all,忽略所有

  • @Deprecated

//#1 方法过期

class Parent1_1{

@Deprecated

public void init(){

}

}

  • @Override 复写父类方法
  • @Override 实现接口方法
  • @SupperssWarings
  • 没有抑制警告

9.3 自定义注解:定义—基本语法

  • 定义注解使用关键字: @interface

1. 定义类: class

2. 定义接口:interface

3. 定义枚举:enum

// #1 定义注解

@interface MyAnno1{

}

  • 定义带有属性的注解

//#2 定义含有属性的注解

@interface MyAnno2{

public String username() default "jack";

}

  • 属性格式:修饰符 返回值类型 属性名() [default 默认值]

4. 修饰符:默认值 public abstract ,且只能是public abstract。

5. 返回值类型:基本类型、字符串String、Class、注解、枚举,以及以上类型的一维数组

6. 属性名:自定义

7. default 默认值:可以省略

  • 完整案例

//#3 完整含属性注解

@interface MyAnno3{

int age() default 1;

String password();

Class clazz();

MyAnno2 myAnno(); // 注解

Color color(); // 枚举

String[] arrs();

}

enum Color{

BLUE,RED;

}

9.4 自定义注解:使用

  • 使用格式:@注解类名( 属性名= 值 , 属性名 = 值 , .....)
  • 注解使用的注意事项:
    • 注解可以没有属性,如果有属性需要使用小括号括住。例如:@MyAnno1 或 @MyAnno1()
    • 属性格式:属性名=属性值,多个属性使用逗号分隔。例如:@MyAnno2(username="rose")
    • 如果属性名为value,且当前只有一个属性,value可以省略。
    • 如果使用多个属性时,k的名称为value不能省略
    • 如果属性类型为数组,设置内容格式为:{ 1,2,3 }。例如:arrs = {"javahelp","wukongjiaocheng"}
    • 如果属性类型为数组,值只有一个{} 可以省略的。例如:arrs = "javahelp"
    • 一个对象上,注解只能使用一次,不能重复使用。

9.5 自定义注解:解析

  • 如果给类、方法等添加注解,如果需要获得注解上设置的数据,那么我们就必须对注解进行解析,JDK提供java.lang.reflect.AnnotatedElement接口允许在运行时通过反射获得注解。
  • 常用方法:
    • boolean isAnnotationPresent(Class annotationClass) 当前对象是否有注解
    • T getAnnotation(Class<T> annotationClass) 获得当前对象上指定的注解
    • Annotation[] getAnnotations() 获得当前对象及其从父类上继承的,所有的注解
    • Annotation[] getDeclaredAnnotations() 获得当前对象上所有的注解
  • 测试

当运行上面程序后,我们希望输出结果是true,但实际是false。TestAnno2类上有@MyAnno1注解,但运行后不能获得,因为每一个自定义注解,需要使用JDK提供的元注解进行修饰才可以真正的使用。

9.6 自定义注解:定义—元注解

  • 元注解:用于修饰注解的注解。(用于修饰自定义注解的JDK提供的注解)
  • JDK提供4种元注解:
    • @Retention 用于确定被修饰的自定义注解生命周期
      • RetentionPolicy.SOURCE 被修饰的注解只能存在源码中,字节码class没有。用途:提供给编译器使用。
      • RetentionPolicy.CLASS 被修饰的注解只能存在源码和字节码中,运行时内存中没有。用途:JVM java虚拟机使用
      • RetentionPolicy.RUNTIME 被修饰的注解存在源码、字节码、内存(运行时)。用途:取代xml配置
    • @Target 用于确定被修饰的自定义注解 使用位置
      • ElementType.TYPE 修饰 类、接口
      • ElementType.CONSTRUCTOR 修饰构造
      • ElementType.METHOD 修饰方法
      • ElementType.FIELD 修饰字段
    • @Documented 使用javaDoc生成 api文档时,是否包含此注解 (了解)
    • @Inherited 如果父类使用被修饰的注解,子类是否继承。(了解)
  • 修改注解类,在运行测试实例,输出结果为:true。

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnno1{

}

9.7 案例:自定义@Test

9.7.1 案例分析

  • 模拟Junit测试,首先需要编写自定义注解@MyTest,并添加元注解,保证自定义注解只能修饰方法,且在运行时可以获得。
  • 其次编写目标类(测试类),然后给目标方法(测试方法)使用@MyTest注解
  • 最后编写测试类,使用main方法模拟Junit的右键运行。

9.7.2 案例实现

  • 步骤1:编写自定义注解类@MyAnno

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnno {

}

  • 步骤2:编写目标类AnnotationDemo
  • 步骤3:编写测试方法

第10章 类加载器

  • 类加载器:类加载器是负责加载类的对象。将class文件(硬盘)加载到内存生成Class对象。

所有的类加载器 都是 java.lang.ClassLoader 的子类

  • 使用 类.class.getClassLoader() 获得加载自己的类加载器
  • 类加载器加载机制:全盘负责委托机制

全盘负责:A类如果要使用B类(不存在),A类加载器C必须负责加载B类。

委托机制:A类加载器如果要加载资源B,必须询问父类加载是否加载。

如果加载,将直接使用。

如果没有机制,自己再加载。

  • 采用 全盘负责委托机制 保证 一个class文件 只会被加载一次,形成一个Class对象。
  • 注意:

如果一个class文件,被两个类加载器加载,将是两个对象。

提示 cn.com.javahelp.Hello 不能强制成 cn.com.javahelp.Hello

h.getClass() -->A h.getClass() -->B

自定义类加载,可以将一个class文件加载多次。

第11章 动态代理

java代理有jdk动态代理、cglib代理,jdk动态代理主要使用的是java反射机制(既java.lang.reflect包)

11.1 JDK动态代理

11.1.1 Proxy类

动态代理:程序运行时,使用JDK提供工具类(Proxy),动态创建一个类,此类一般用于代理。

代理:你 -- 代理(增强) -- 厂商

代理类: 目标类:被代理的

动态代理使用前提:必须有接口

Object proxyObj = Proxy.newProxyInstance(参数1,参数2,参数3);

参数1:ClassLoader,负责将动态创建类,加载到内存。 当前类.class.getClassLoader();

参数2:Class[] interfaces ,代理类需要实现的所有接口(确定方法),被代理类实例.getClass().getInterfaces();

参数3:InvocationHandler, 请求处理类,代理类不具有任何功能,代理类的每一个方法执行时,调用处理类invoke方法。

voke(Object proxy ,Method ,Object[] args)

参数1:代理实例

参数2:当前执行的方法

参数3:方法实际参数。

public interface UserService {

public void addUser();

public void updateUser();

}

public class UserServiceImpl implements UserService {

@Override

public void addUser() {

System.out.println("addUser");

}

@Override

public void updateUser() {

System.out.println("updateUser");

}

}

public class TextP {

public static void main(String[] args) {

// 1 目标类实例

final UserService userService = new UserServiceImpl();

// 2 代理类

UserService proxyService = (UserService) Proxy.newProxyInstance(TextP.class.getClassLoader(),

userService.getClass().getInterfaces(), new InvocationHandler() {

@Override

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

// 增强

// 1 获得方法名

String methodName = method.getName();

// 2 判断

if ("addUser".equals(methodName)) {

// 1) 前

System.out.println("前");

// 2) 执行

Object obj = method.invoke(userService, args);

// 3) 后

System.out.println("后");

return obj;

}

// 放行:执行目标类的方法

return method.invoke(userService, args);

}

});

// 3 执行代理类

proxyService.addUser();

proxyService.updateUser();

}

}

11.1.2 动态代理原理

原理是(歌手、经纪人做例子):

  • 建立一个公共的接口,比如:歌手public interface Singer;
  • 用具体的类实现接口,比如:周杰伦,他是歌手所以实现Singer这个类,class MySinger implements Singer
  • 建立代理类,这里也就是经纪人,他需要实现InvocationHandler类,并重写invoke方法
  • 这样当有什么事情,要找周杰伦(具体类)的时候,就必须先到经纪人(代理类)那里处理,代理人在决定要不要与你见面(该方法要不要执行)
  • 歌手接口
  • 具体的歌手
  • 代理类(经纪人)
  • 测试(为什么要间接口能,下面你会发现代理返回的是他们的接口类,这要一个代理类,就可以代理多个类,只要该类是同个一个接口的是实现)

11.2 Cglib动态代理 (了解)

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

示例

1、BookFacadeCglib.java

2、BookCadeImpl1.java

3、BookFacadeProxy.java

4、TestCglib.java

第4天数据库介绍&SQL基础

第12章 数据库介绍

12.1 数据库概述

  • 什么是数据库

数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储起来,用户可以对数据库中的数据进行增加,修改,删除及查询操作。

  • 什么是数据库管理系统

数据库管理系统(DataBase Management System,DBMS):指一种操作和管理数据库的大型软件,用于建立、使用和维护数据库,对数据库进行统一管理和控制,以保证数据库的安全性和完整性。用户通过数据库管理系统访问数据库中表内的数据。

  • 数据库与数据库管理系统的关系

12.2 数据库表

数据库中以表为组织单位存储数据。

表类似我们的Java类,每个字段都有对应的数据类型。

那么用我们熟悉的java程序来与关系型数据对比,就会发现以下对应关系。

类----------表

类中属性----------表中字段

对象----------记录

12.3 表数据

根据表字段所规定的数据类型,我们可以向其中填入一条条的数据,而表中的每条数据类似类的实例对象。表中的一行一行的信息我们称之为记录。

  • 表记录与java类对象的对应关系

12.4 常见数据库

  • 常见的数据库管理系统

MYSQL :开源免费的数据库,小型的数据库.已经被Oracle收购了.MySQL6.x版本也开始收费。

Oracle :收费的大型数据库,Oracle公司的产品。Oracle收购SUN公司,收购MYSQL。

DB2 :IBM公司的数据库产品,收费的。常应用在银行系统中.

SQLServer:MicroSoft 公司收费的中型的数据库。C#、.net等语言常使用。

SyBase :已经淡出历史舞台。提供了一个非常专业数据建模的工具PowerDesigner。

SQLite : 嵌入式的小型数据库,应用在手机端。

常用数据库:MYSQL,Oracle.

这里使用MySQL数据库。MySQL中可以有多个数据库,数据库是真正存储数据的地方。

第13章 MySql数据库

13.1 MySql安装

  • 安装

参考MySQL安装图解.doc 官网 http://www.javahelp.com.cn下载

安装后,MySQL会以windows服务的方式为我们提供数据存储功能。开启和关闭服务的操作:右键点击我的电脑→管理→服务→可以找到MySQL服务开启或停止。

也可以在DOS窗口,通过命令完成MySQL服务的启动和停止(必须以管理运行cmd命令窗口)

13.2 登录MySQL数据库

MySQL是一个需要账户名密码登录的数据库,登陆后使用,它提供了一个默认的root账号,使用安装时设置的密码即可登录。

格式1:cmd> mysql –u用户名 –p密码

例如:mysql -uroot –proot

格式2:cmd> mysql --host=ip地址 --user=用户名 --password=密码

例如:mysql --host=127.0.0.1 --user=root --password=root

13.3 SQLyog(MySQL图形化开发工具)

  • 安装:

提供的SQLyog软件为免安装版,可直接使用

  • 使用:

输入用户名、密码,点击连接按钮,进行访问MySQL数据库进行操作

在Query窗口中,输入SQL代码,选中要执行的SQL代码,按F8键运行,或按执行按钮运行。

第14章 SQL语句

14.1 SQL概述

14.1.1 SQL语句介绍

数据库是不认识JAVA语言的,但是我们同样要与数据库交互,这时需要使用到数据库认识的语言SQL语句,它是数据库的代码。

结构化查询语言(Structured Query Language)简称SQL,是关系型数据库管理系统都需要遵循的规范。不同的数据库生产厂商都支持SQL语句,但都有特有内容。

14.1.2 SQL语句分类

  • SQL分类:
    • 数据定义语言:简称DDL(Data Definition Language),用来定义数据库对象:数据库,表,列等。关键字:create,alter,drop等
    • 数据操作语言:简称DML(Data Manipulation Language),用来对数据库中表的记录进行更新。关键字:insert,delete,update等
    • 数据控制语言:简称DCL(Data Control Language),用来定义数据库的访问权限和安全级别,及创建用户。
    • 数据查询语言:简称DQL(Data Query Language),用来查询数据库中表的记录。关键字:select,from,where等

14.1.3 SQL通用语法

  • SQL语句可以单行或多行书写,以分号结尾
  • 可使用空格和缩进来增强语句的可读性
  • MySQL数据库的SQL语句不区分大小写,关键字建议使用大写
    • 例如:SELECT * FROM user。
  • 同样可以使用/**/的方式完成注释
  • MySQL中的我们常使用的数据类型如下

详细的数据类型如下(不建议详细阅读!)

分类

类型名称

说明

整数类型

tinyInt

很小的整数

smallint

小的整数

mediumint

中等大小的整数

int(integer)

普通大小的整数

小数类型

float

单精度浮点数

double

双精度浮点数

decimal(m,d)

压缩严格的定点数

日期类型

year

YYYY 1901~2155

time

HH:MM:SS -838:59:59~838:59:59

date

YYYY-MM-DD 1000-01-01~9999-12-3

datetime

YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00~ 9999-12-31 23:59:59

timestamp

YYYY-MM-DD HH:MM:SS 1970~01~01 00:00:01 UTC~2038-01-19 03:14:07UTC

文本、二进制类型

CHAR(M)

M为0~255之间的整数

VARCHAR(M)

M为0~65535之间的整数

TINYBLOB

允许长度0~255字节

BLOB

允许长度0~65535字节

MEDIUMBLOB

允许长度0~167772150字节

LONGBLOB

允许长度0~4294967295字节

TINYTEXT

允许长度0~255字节

TEXT

允许长度0~65535字节

MEDIUMTEXT

允许长度0~167772150字节

LONGTEXT

允许长度0~4294967295字节

VARBINARY(M)

允许长度0~M个字节的变长字节字符串

BINARY(M)

允许长度0~M个字节的定长字节字符串

14.2 DDL之数据库操作:database

14.2.1 创建数据库

格式:

* create database 数据库名;

* create database 数据库名 character set 字符集;

例如:

#创建数据库 数据库中数据的编码采用的是安装数据库时指定的默认编码 utf8

CREATE DATABASE webdb_1;

#创建数据库 并指定数据库中数据的编码

CREATE DATABASE webdb_2 CHARACTER SET utf8;

14.2.2 查看数据库

查看数据库MySQL服务器中的所有的数据库:

show databases;

查看某个数据库的定义的信息:

show create database 数据库名;

例如:

show create database webdb_1;

14.2.3 删除数据库

drop database 数据库名称;

例如:

drop database webdb_2;

14.2.4 使用数据库

查看正在使用的数据库:

select database();

其他的数据库操作命令

切换数据库:

use 数据库名;

例如:

use webdb_1;

14.3 DDL之表操作:table

14.3.1 创建表

  • 格式:

create table 表名(

字段名 类型(长度) [约束],

字段名 类型(长度) [约束],

...

);

类型:

varchar(n) 字符串

int 整形

double 浮点

date 时间

timestamp 时间戳

约束:

primary key 主键,被主键修饰字段中的数据,不能重复、不能为null。

例如:

###创建分类表

CREATE TABLE category (

cid INT primary key, #分类ID

cname VARCHAR(100) #分类名称

);

14.3.2 查看表

查看数据库中的所有表:

格式:show tables;

查看表结构:

格式:desc 表名;

例如:desc sort;

14.3.3 删除表

格式:drop table 表名;

例如:drop table category;

14.3.4 修改表结构格式:

  • alter table 表名 add 列名 类型(长度) [约束];

作用:修改表添加列.

例如:

#1,为分类表添加一个新的字段为 分类描述 varchar(20)

ALTER TABLE category ADD `desc` VARCHAR(20);

  • alter table 表名 modify 列名 类型(长度) 约束;

作用:修改表修改列的类型长度及约束.

例如:

#2, 为分类表的描述字段进行修改,类型varchar(50) 添加约束 not null

ALTER TABLE category MODIFY `desc` VARCHAR(50) NOT NULL;

  • alter table 表名 change 旧列名 新列名 类型(长度) 约束;

作用:修改表修改列名.

例如:

#3, 为分类表的分类名称字段进行更换 更换为 snamesname varchar(30)

ALTER TABLE category CHANGE `desc` description VARCHAR(30);

  • alter table 表名 drop 列名;

作用:修改表删除列.

例如:

#4, 删除分类表中snamename这列

ALTER TABLE category DROP description;

  • rename table 表名 to 新表名;

作用:修改表名

例如:

#5, 为分类表category 改名成 category2

RENAME TABLE category TO category2;

  • alter table 表名 character set 字符集;

作用:修改表的字符集

例如:

#6, 为分类表 category 的编码表进行修改,修改成 gbk

ALTER TABLE category CHARACTER SET gbk;

14.4 DML数据操作语言

14.4.1 插入表记录:insert

  • 语法:

-- 向表中插入某些字段

insert into 表 (字段1,字段2,字段3..) values (值1,值2,值3..);

--向表中插入所有字段,字段的顺序为创建表时的顺序

insert into 表 values (值1,值2,值3..);

  • 注意:
    • 值与字段必须对应,个数相同,类型相同
    • 值得数据大小必须在字段的长度范围内
    • 除了数值类型外,其它的字段类型的值必须使用引号引起。(建议单引号)
    • 如果要插入空值,可以不写字段,或者插入 null。
  • 例如:

INSERT INTO category(cid,cname) VALUES('c001','电器');

INSERT INTO category(cid,cname) VALUES('c002','服饰');

INSERT INTO category(cid,cname) VALUES('c003','化妆品');

INSERT INTO category(cid,cname) VALUES('c004','书籍');

INSERT INTO category(cid) VALUES('c002');

INSERT INTO category(cname) VALUES('耗材');

14.4.2 更新表记录:update

用来修改指定条件的数据,将满足条件的记录指定列修改为指定值

  • 语法:

--更新所有记录的指定字段

update 表名 set 字段名=值,字段名=值,...;

--更新符号条件记录的指定字段

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

  • 注意:
    • 列名的类型与修改的值要一致.
    • 修改值得时候不能超过最大长度.
    • 除了数值类型外,其它的字段类型的值必须使用引号引起

14.4.3 删除记录:delete

  • 语法:

delete from 表名 [where 条件];

或者

truncate table 表名;

  • 面试题:

删除表中所有记录使用delete from 表名; 还是用truncate table 表名;

删除方式:delete 一条一条删除,不清空auto_increment记录数。

truncate 直接将表删除,重新建表,auto_increment将置为零,从新开始。

14.5 DOS操作数据乱码解决

我们在dos命令行操作中文时,会报错

insert into category(cid,cname) values(‘c010’,’中文’);

ERROR 1366 (HY000): Incorrect string value: '\xB7\xFE\xD7\xB0' for column 'cname' at row 1

解决方案1:在cmd命令窗口中输入命令,此操作当前窗口有效,为临时方案。

set names gbk;

解决方案2:安装目录下修改my.ini文件,重启服务所有地方生效。[不建议]

错误原因:因为mysql的客户端设置编码是utf8,而系统的cmd窗口编码是gbk

1)查看MySQL内部设置的编码

show variables like 'character%'; 查看所有mysql的编码

2)修改client、connection、results的编码一致(GBK编码)

client connetion result 和客户端保持一致,都为GBK

l 将客户端编码修改为gbk.

#方式1:单独设置

set character_set_client=gbk;

set character_set_connection=gbk;

set character_set_results=gbk;

#方式2:快捷设置

set names gbk;

14.6 DQL数据查询语言

14.6.1 准备工作

#创建商品表:

create table product(

pid int primary key,

pname varchar(20),

price double,

category_id varchar(32)

);

INSERT INTO product(pid,pname,price,category_id) VALUES(1,'联想',5000,'c001');

INSERT INTO product(pid,pname,price,category_id) VALUES(2,'海尔',3000,'c001');

INSERT INTO product(pid,pname,price,category_id) VALUES(3,'雷神',5000,'c001');

INSERT INTO product(pid,pname,price,category_id) VALUES(4,'JACK JONES',800,'c002');

INSERT INTO product(pid,pname,price,category_id) VALUES(5,'真维斯',200,'c002');

INSERT INTO product(pid,pname,price,category_id) VALUES(6,'花花公子',440,'c002');

INSERT INTO product(pid,pname,price,category_id) VALUES(7,'劲霸',2000,'c002');

INSERT INTO product(pid,pname,price,category_id) VALUES(8,'香奈儿',800,'c003');

INSERT INTO product(pid,pname,price,category_id) VALUES(9,'相宜本草',200,'c003');

INSERT INTO product(pid,pname,price,category_id) VALUES(10,'面霸',5,'c003');

INSERT INTO product(pid,pname,price,category_id) VALUES(11,'好想你枣',56,'c004');

INSERT INTO product(pid,pname,price,category_id) VALUES(12,'香飘飘奶茶',1,'c005');

INSERT INTO product(pid,pname,price,category_id) VALUES(13,'果9',1,NULL);

14.6.2 语法:

select [distinct]

* | 列名,列名

from 表

where 条件

14.6.3 简单查询

1.查询所有的商品. select * from product;

2.查询商品名和商品价格. select pname,price from product;

3.别名查询.使用的关键字是as(as可以省略的).

3.1表别名: select * from product as p;

3.2列别名:select pname as pn from product;

4.去掉重复值. select distinct price from product;

5.查询结果是表达式(运算查询):将所有商品的价格+10元进行显示.

select pname,price+10 from product;

14.6.4 条件查询

比较运算符

> < <= >= = <>

大于、小于、大于(小于)等于、不等于

BETWEEN ...AND...

显示在某一区间的值(含头含尾)

IN(set)

显示在in列表中的值,例:in(100,200)

LIKE ‘张pattern’

模糊查询,Like语句中,% 代表零个或多个任意字符,_ 代表一个字符,例如:first_name like ‘_a%’;

IS NULL

判断是否为空

逻辑运算符

and

多个条件同时成立

or

多个条件任一成立

not

不成立,例:where not(salary>100);

#查询商品名称为“花花公子”的商品所有信息:

SELECT * FROM product WHERE pname = '花花公子'

#查询价格为800商品

SELECT * FROM product WHERE price = 800

#查询价格不是800的所有商品

SELECT * FROM product WHERE price != 800

SELECT * FROM product WHERE price <> 800

SELECT * FROM product WHERE NOT(price = 800)

#查询商品价格大于60元的所有商品信息

SELECT * FROM product WHERE price > 60;

#查询商品价格在200到1000之间所有商品

SELECT * FROM product WHERE price >= 200 AND price <=1000;

SELECT * FROM product WHERE price BETWEEN 200 AND 1000;

#查询商品价格是200或800的所有商品

SELECT * FROM product WHERE price = 200 OR price = 800;

SELECT * FROM product WHERE price IN (200,800);

#查询含有'霸'字的所有商品

SELECT * FROM product WHERE pname LIKE '%霸%';

#查询以'香'开头的所有商品

SELECT * FROM product WHERE pname LIKE '香%';

#查询第二个字为'想'的所有商品

SELECT * FROM product WHERE pname LIKE '_想%';

#商品没有分类的商品

SELECT * FROM product WHERE category_id IS NULL

#查询有分析的商品

SELECT * FROM product WHERE category_id IS NOT NULL

第5天SQL语句高级

第15章 SQL语句查询

15.1 排序

通过order by语句,可以将查询出的结果进行排序。放置在select语句的最后。

格式:

SELECT * FROM 表名 ORDER BY 排序字段 ASC|DESC;

ASC 升序 (默认)

DESC 降序

#1.使用价格排序(降序)

SELECT * FROM product ORDER BY price DESC;

#2.在价格排序(降序)的基础上,以分类排序(降序)

SELECT * FROM product ORDER BY price DESC,category_id DESC;

#3.显示商品的价格(去重复),并排序(降序)

SELECT DISTINCT price FROM product ORDER BY price DESC;

15.2 聚合

之前我们做的查询都是横向查询,它们都是根据条件一行一行的进行判断,而使用聚合函数查询是纵向查询,它是对一列的值进行计算,然后返回一个单一的值;另外聚合函数会忽略空值。

今天我们学习如下五个聚合函数:

  • count:统计指定列不为NULL的记录行数;
  • sum:计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;
  • max:计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
  • min:计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
  • avg:计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;

#1 查询商品的总条数

SELECT COUNT(*) FROM product;

#2 查询价格大于200商品的总条数

SELECT COUNT(*) FROM product WHERE price > 200;

#3 查询分类为'c001'的所有商品的总和

SELECT SUM(price) FROM product WHERE category_id = 'c001';

#4 查询分类为'c002'所有商品的平均价格

SELECT AVG(price) FROM product WHERE category_id = 'c002';

#5 查询商品的最大价格和最小价格

SELECT MAX(price),MIN(price) FROM product;

15.3 分组

分组查询是指使用group by字句对查询信息进行分组。

  • 格式:

SELECT 字段1,字段2… FROM 表名 GROUP BY分组字段 HAVING 分组条件;

分组操作中的having子语句,是用于在分组后对数据进行过滤的,作用类似于where条件。

  • having与where的区别:
    • having是在分组后对数据进行过滤.
    • where是在分组前对数据进行过滤
    • having后面可以使用分组函数(统计函数)
    • where后面不可以使用分组函数。

#1 统计各个分类商品的个数

SELECT category_id ,COUNT(*) FROM product GROUP BY category_id ;

#2 统计各个分类商品的个数,且只显示个数大于1的信息

SELECT category_id ,COUNT(*) FROM product GROUP BY category_id HAVING COUNT(*) > 1;

第16章 SQL备份与恢复

16.1 SQL备份

选中数据库,右键 ”备份/导出” , 指定导出路径,保存成.sql文件即可。

16.2 SQL恢复

数据库列表区域右键“从SQL转储文件导入数据库”, 指定要执行的SQL文件,执行即可。

第17章 SQL约束

17.1 主键约束

PRIMARY KEY 约束唯一标识数据库表中的每条记录。

主键必须包含唯一的值。

主键列不能包含 NULL 值。

每个表都应该有一个主键,并且每个表只能有一个主键。

17.1.1 添加主键约束

  • 方式一:创建表时,在字段描述处,声明指定字段为主键:

CREATE TABLE Persons

(

Id_P int PRIMARY KEY,

LastName varchar(255),

FirstName varchar(255),

Address varchar(255),

City varchar(255)

)

  • 方式二:创建表时,在constraint约束区域,声明指定字段为主键:
    • 格式:[constraint 名称] primary key (字段列表)
    • 关键字constraint可以省略,如果需要为主键命名,constraint不能省略,主键名称一般没用。
    • 字段列表需要使用小括号括住,如果有多字段需要使用逗号分隔。声明两个以上字段为主键,我们称为联合主键。

CREATE TABLE Persons

(

FirstName varchar(255),

LastName varchar(255),

Address varchar(255),

City varchar(255),

CONSTRAINT pk_PersonID PRIMARY KEY (FirstName,LastName)

)

CREATE TABLE Persons

(

FirstName varchar(255),

LastName varchar(255),

Address varchar(255),

City varchar(255),

PRIMARY KEY (FirstName,LastName)

)

  • 方式三:创建表之后,通过修改表结构,声明指定字段为主键:

ALTER TABLE Persons ADD [CONSTRAINT 名称] PRIMARY KEY (字段列表)

CREATE TABLE Persons

(

FirstName varchar(255),

LastName varchar(255),

Address varchar(255),

City varchar(255)

)

ALTER TABLE Persons ADD PRIMARY KEY (FirstName,LastName)

17.1.2 删除主键约束

如需撤销 PRIMARY KEY 约束,请使用下面的 SQL:

ALTER TABLE Persons DROP PRIMARY KEY

17.2 自动增长列

我们通常希望在每次插入新记录时,数据库自动生成字段的值。

我们可以在表中使用 auto-increment(自动增长列)关键字,自动增长列类型必须是整形,自动增长列必须为键(一般是主键)。

  • 下列 SQL 语句把 "Persons" 表中的 "P_Id" 列定义为 auto-increment 主键

CREATE TABLE Persons

(

P_Id int PRIMARY KEY AUTO_INCREMENT,

LastName varchar(255),

FirstName varchar(255),

Address varchar(255),

City varchar(255)

)

l 向persons添加数据时,可以不为P_Id字段设置值,也可以设置成null,数据库将自动维护主键值:

INSERT INTO Persons (FirstName,LastName) VALUES ('Bill','Gates')

INSERT INTO Persons (P_Id,FirstName,LastName) VALUES (NULL,'Bill','Gates')

  • 面试:delete和truncate的区别
    • Delete删除表中的数据,但不重置auto-increment记录数。
    • Truncate删除表中的数据,auto-increment记录数将重置。Truncate其实先删除表然后再创建表。
  • 扩展:默认地,AUTO_INCREMENT 的开始值是 1,如果希望修改起始值,请使用下列 SQL 语法:

ALTER TABLE Persons AUTO_INCREMENT=100

17.3 非空约束

NOT NULL 约束强制列不接受 NULL 值。

NOT NULL 约束强制字段始终包含值。这意味着,如果不向字段添加值,就无法插入新记录或者更新记录。

  • 下面的 SQL 语句强制 "Id_P" 列和 "LastName" 列不接受 NULL 值:

CREATE TABLE Persons

(

Id_P int NOT NULL,

LastName varchar(255) NOT NULL,

FirstName varchar(255),

Address varchar(255),

City varchar(255)

)

17.4 唯一约束

UNIQUE 约束唯一标识数据库表中的每条记录。

UNIQUE 和 PRIMARY KEY 约束均为列或列集合提供了唯一性的保证。

PRIMARY KEY 拥有自动定义的 UNIQUE 约束。

请注意,每个表可以有多个 UNIQUE 约束,但是每个表只能有一个 PRIMARY KEY 约束。

17.4.1 添加唯一约束

与主键添加方式相同,共有3种,

  • 方式1:创建表时,在字段描述处,声明唯一:

CREATE TABLE Persons

(

Id_P int UNIQUE,

LastName varchar(255) NOT NULL,

FirstName varchar(255),

Address varchar(255),

City varchar(255)

)

  • 方式2:创建表时,在约束区域,声明唯一:

CREATE TABLE Persons

(

Id_P int,

LastName varchar(255) NOT NULL,

FirstName varchar(255),

Address varchar(255),

City varchar(255),

CONSTRAINT 名称UNIQUE (Id_P)

)

  • 方式3:创建表后,修改表结构,声明字段唯一:

ALTER TABLE Persons ADD [CONSTRAINT 名称] UNIQUE (Id_P)

17.4.2 删除唯一约束

  • 如需撤销 UNIQUE 约束,请使用下面的 SQL: ALTER TABLE Persons DROP INDEX 名称
  • 如果添加唯一约束时,没有设置约束名称,默认是当前字段的字段名。

17.5 外键约束

FOREIGN KEY 表示外键约束,将在多表中学习。

第18章 多表操作

实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系,接下来我们将在单表的基础上,一起学习多表方面的知识。

18.1 表与表之间的关系

  • 一对多关系:
    • 常见实例:客户和订单,分类和商品,部门和员工.
    • 一对多建表原则:在从表(多方)创建一个字段,字段作为外键指向主表(一方)的主键.
  • 多对多关系:
    • 常见实例:学生和课程、用户和角色
    • 多对多关系建表原则:需要创建第三张表,中间表中至少两个字段,这两个字段分别作为外键指向各自一方的主键.
  • 一对一关系:(了解)
    • 在实际的开发中应用不多.因为一对一可以创建成一张表.
    • 两种建表原则:
      • 外键唯一:主表的主键和从表的外键(唯一),形成主外键关系,外键唯一unique。
      • 外键是主键:主表的主键和从表的主键,形成主外键关系。

18.2 外键约束

现在我们有两张表“分类表”和“商品表”,为了表明商品属于哪个分类,通常情况下,我们将在商品表上添加一列,用于存放分类cid的信息,此列称为:外键

此时“分类表category”称为:主表,“cid”我们称为主键。“商品表products”称为:从表,category_id称为外键。我们通过主表的主键和从表的外键来描述主外键关系,呈现就是一对多关系。

外键特点:

  • 从表外键的值是对主表主键的引用。
  • 从表外键类型,必须与主表主键类型一致。

  • 声明外键约束

语法:alter table 从表 add [constraint] [外键名称] foreign key (从表外键字段名) references 主表 (主表的主键);

[外键名称] 用于删除外键约束的,一般建议“_fk”结尾

alter table 从表 drop foreign key 外键名称

  • 使用外键目的:

保证数据的一致性和完整性

18.3 一对多操作

18.3.1 分析

  • category分类表,为一方,也就是主表,必须提供主键cid
  • products商品表,为多方,也就是从表,必须提供外键category_id

18.3.2 实现:分类和商品

###创建分类表

create table category(

cid varchar(32) PRIMARY KEY ,

cname varchar(100) #分类名称

);

# 商品表

CREATE TABLE `products` (

`pid` varchar(32) PRIMARY KEY ,

`name` VARCHAR(40) ,

`price` DOUBLE

);

#添加外键字段

alter table products add column category_id varchar(32);

#添加约束

alter table products add constraint product_fk foreign key (category_id) references category (cid);

18.3.3 操作

#1 向分类表中添加数据

INSERT INTO category (cid ,cname) VALUES('c001','服装');

#2 向商品表添加普通数据,没有外键数据,默认为null

INSERT INTO products (pid,pname) VALUES('p001','商品名称');

#3 向商品表添加普通数据,含有外键信息(数据存放在)

INSERT INTO products (pid ,pname ,category_id) VALUES('p002','商品名称2','c001');

#4 向商品表添加普通数据,含有外键信息(数据不存在) -- 不能异常

INSERT INTO products (pid ,pname ,category_id) VALUES('p003','商品名称2','c999');

#5 删除指定分类(分类被商品使用) -- 执行异常

DELETE FROM category WHERE cid = 'c001';

18.4 多对多

18.4.1 分析

  • 商品和订单多对多关系,将拆分成两个一对多。
  • products商品表,为其中一个一对多的主表,需要提供主键pid
  • orders 订单表,为另一个一对多的主表,需要提供主键oid
  • orderitem中间表,为另外添加的第三张表,需要提供两个外键oid和pid

18.4.2 实现:订单和商品

### 商品表[已存在]

### 订单表

create table `orders`(

`oid` varchar(32) PRIMARY KEY ,

`totalprice` double #总计

);

### 订单项表

create table orderitem(

oid varchar(50),-- 订单id

pid varchar(50)-- 商品id

);

###---- 订单表和订单项表的主外键关系

alter table `orderitem` add constraint orderitem_orders_fk foreign key (oid) references orders(oid);

###---- 商品表和订单项表的主外键关系

alter table `orderitem` add constraint orderitem_product_fk foreign key (pid) references products(pid);

### 联合主键(可省略)

alter table `orderitem` add primary key (oid,pid);

18.4.3 操作

#1 向商品表中添加数据

INSERT INTO products (pid,pname) VALUES('p003','商品名称');

#2 向订单表中添加数据

INSERT INTO orders (oid ,totalprice) VALUES('x001','998');

INSERT INTO orders (oid ,totalprice) VALUES('x002','100');

#3向中间表添加数据(数据存在)

INSERT INTO orderitem(pid,oid) VALUES('p001','x001');

INSERT INTO orderitem(pid,oid) VALUES('p001','x002');

INSERT INTO orderitem(pid,oid) VALUES('p002','x002');

#4删除中间表的数据

DELETE FROM orderitem WHERE pid='p002' AND oid = 'x002';

#5向中间表添加数据(数据不存在) -- 执行异常

INSERT INTO orderitem(pid,oid) VALUES('p002','x003');

#6删除商品表的数据 -- 执行异常

DELETE FROM products WHERE pid = 'p001';

原文发布于微信公众号 - Java帮帮(javahelp)

原文发表时间:2018-06-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员叨叨叨

【PHP】Propel的使用,看这一篇就够了

本文为学习Propel框架使用的笔记,默认已经安装好Propel环境,若有读者不知如何安装Propel,可参考《听说你PHP配置Composer遇到了一些困境》...

48150
来自专栏编程

Web工程下读取文件的几种方法

1、读取文件系统路径文件 * 一定要使用绝对路径 String fileName = getServletContext().getRealPath("/in...

21360
来自专栏别先生

Hibernate的核心对象关系映射

Hibernate的核心就是对象关系映射: 加载映射文件的两种方式:   第一种:<mapping resource="com/bie/lesson02/c...

24660
来自专栏IT笔记

Hibernate合并查询结果集为实体类

用过mybatis的小伙伴可能都知道,我们可以查询两个表的部分字段合并为一个实体。然而用了Hibernate这么久了,居然还不知道也有此神器。 ? hibern...

45360
来自专栏大数据和云计算技术

Spring+Mybatis+Maven+Mysql编程实战

image.png 封面是Niagara Falls,世界第一大瀑布。 概述 这篇文章主要讲解使用eclipse对Spring+Maven+Mybatis+My...

33860
来自专栏用户2442861的专栏

初学Redis(2)——用Redis作为Mysql数据库的缓存

http://blog.csdn.net/qtyl1988/article/details/39519951

19720
来自专栏吴伟祥

字段规范 原

5810
来自专栏Hongten

python开发_pickle

pickle模块使用的数据格式是python专用的,并且不同版本不向后兼容,同时也不能被其他语言说识别。要和其他语言交互,可以使用内置的json包使用pickl...

11520
来自专栏xingoo, 一个梦想做发明家的程序员

AngularJS API之toJson 对象转为JSON

toJson()能把对象序列化为json 方法讲解 这个方法最多支持2个参数: angular.toJson(obj, pretty); obj 是想要转换的...

25550
来自专栏芋道源码1024

数据库分库分表中间件 Sharding-JDBC 源码分析 —— SQL 路由(二)之分库分表路由

本文主要基于 Sharding-JDBC 1.5.0 正式版 1. 概述 2. SQLRouteResult 3. 路由策略 x 算法 4. SQL 路由 5....

89960

扫码关注云+社区

领取腾讯云代金券