Hibernate學習筆記


Hibernate

一、hibernate是什么

  1. 一種框架,一種orm框架
    (objext relation mapping)對象關系映射框架。
  2. hibernate處於項目的持久層位置,又叫持久化框架。
  3. hibernate實際上是對jdbc進行輕量級的封裝。

二、需求

  1. 切換數據庫需要重寫編寫sql。
  2. 使用jdbc操作數據庫語句編寫比較麻煩。
  3. 讓程序員只關注業務邏輯,不再關心數據庫。

三、快速入門案例

使用手動配置hibernate方式開發一個hibernate項目,完成相關操作。

開發流程

  1. 創建一個項目
  2. 畫出簡單的項目框架圖
  3. 引入Hibernate包
  4. 開發Hibernate三種方式
  • 由Domain object --> mapping --> db。 (官方推薦)
  • 由DB開始,用工具生成Mapping的Domain object。(使用較多)
  • 由映射文件開始。

我們使用第二種方式
首先在hibernate數據庫下創建student表

create table student(
id int primary key,
name varchar(20) not null,
age varchar(20) not null,
);

5.開發domain對象 和對象關系映射
對象關系映射文件,用於指定domain對象和表的映射關系,該文件的取名有規范,domain對象hbm.xml,一般和domain對象同一包下。

<?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE hibernate-mapping PUBLIC
     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  
 <hibernate-mapping package="com.sun.hibernate.model">
     <class name="Student">
         <id name="id"></id>
         <property name="name"></property>
         <property name="age"></property>
     </class>
 </hibernate-mapping>

6.手動配置hibernate.cfg.xml文件,該文件用於配置連接的數據庫類型,diver,用戶名,密碼....同時管理對象關系映射文件和該文件的名稱,這個文件一般放在src目錄下。

<?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>
   <session-factory>
    
   <!-- Database connection settings -->
   <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
   <property name="connection.url">jdbc:mysql://localhost/hibernate</property>
   <property name="connection.username">root</property>
   <property name="connection.password"></property>
        
   <!-- JDBC connection pool (use the built-in) -->
   <!-- <property name="connection.pool_size">1</property> -->
        
   <!-- SQL dialect -->
   <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        
   <!-- Echo all executed SQL to stdout -->
   <property name="show_sql">true</property>
        
   <!-- Enable Hibernate's automatic session context management -->
   <!--<property name="current_session_context_class">thread</property>-->
        
   <!-- Drop and re-create the database schema on startup -->
   <!-- <property name="hbm2ddl.auto">create</property> -->
        
   <!-- Disable the second-level cache -->
   <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    
   <mapping resource="com/sun/hibernate/model/Student.hbm.xml"/>
      
     </session-factory>
 </hibernate-configuration>

7. 創建對應的student模型

package com.sun.hibernate.model;

public class Student {
	private int id;
	private String name;
	private int age;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	

}

8.測試方法(向數據庫中添加一條數據)

package com.sun.hibernate.model;


import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;

public class StudentTest {
	public static void main(String[] args){
		Student s = new Student();
		s.setId(1);
		s.setName("s1");
		s.setAge(2);
		
		//1.創建Configuration ,該對象用於讀取hibernate.cfg.xml,並完成初始化
		Configuration  cfg = new Configuration();
		//2.創建SessionFactory<這是一個會話工廠,是一個重量級對象>
		SessionFactory sf = cfg.configure().buildSessionFactory();
		//3.創建一個session,相當於jdbc Connection<不是jsp中的那個session>
		Session session = sf.openSession();
		//4.對hibernate而言,要求程序員在進行增加,刪除,修改時必須使用事物提交
		session.beginTransaction();
		session.save(s);	//insert into ...  <sql語句被hibernate封裝了>
		session.getTransaction().commit();
		session.close();
		sf.close();
	}
}

直接運行StudentTest就可以將數據插入到數據庫中了。

四、 hibernate緩存原理

詳細信息

1.session緩存(一級緩存)

Session內置不能被卸載,Session的緩存是事務范圍的緩存(Session對象的生命周期通常對應一個數據庫事務或者一個應用事務)。
一級緩存中,持久化類的每個實例都具有唯一的OID。

2.二級緩存

第二級緩存是可選的,是一個可配置的插件,默認下SessionFactory不會啟用這個插件。
Hibernate提供了org.hibernate.cache.CacheProvider接口,它充當緩存插件與Hibernate之間的適配器。

什么樣的數據適合存放到第二級緩存中?   

  1. 很少被修改的數據   
  2. 不是很重要的數據,允許出現偶爾並發的數據   
  3. 不會被並發訪問的數據   
  4. 常量數據   
    不適合存放到第二級緩存的數據?   
  5. 經常被修改的數據   
  6. 絕對不允許出現並發訪問的數據,如財務數據,絕對不允許出現並發   
  7. 與其他應用共享的數據。

Hibernate查找對象如何應用緩存?
當Hibernate根據ID訪問數據對象的時候,首先從Session一級緩存中查;
查不到,如果配置了二級緩存,那么從二級緩存中查;
如果都查不到,再查詢數據庫,把結果按照ID放入到緩存刪除、更新、增加數據的時候,同時更新緩存。

五、 Query接口

通過Query接口我們可以完成更加復雜的查詢任務

快速入門

/*獲取query應用【這里student不是表,而是domain】
where后面的條件可以是一個類的屬性名,也可以是表的字段,按照hibernate規定,我們還是應該使用類的屬性名*/
	Query query = session.createQuery("from Teacher  where id = 2");
	//通過list方法獲取結果,這個list會自動將封裝成對應的dommain
	//所以我們jdbc進行二次封裝的工作沒有
	List<Teacher> list = query.list();
		for(Teacher tea: list){
			System.out.println(tea.getName() + "  " + tea.getAge());
		}

六、 criteria接口簡單使用

快速入門

Criteria cri = session.createCriteria(Teacher.class).setMaxResults(4);
			List<Teacher> list = cri.list();
			for(Teacher tea:list){
				System.out.println(tea.getId() + "  " + tea.getName());
			}

七、HQL

(hibernate query language)

1.需求

在現有的只是基礎上,對對象的批量刪除,修改,查詢還不能很方便的實現。

模擬創建表

2.list

查詢所有對象

List<Student> list =  session.createQuery("from Student").list();

3.uniqueResult

如果檢索一個對象,明確知道最多只有一個,則建議使用該方法。
具體用法:

Student stu =  (Student) session.createQuery(" from Student where sid = 20040001").uniqueResult();

4.HQL常見用法

distinct的用法:(用於過濾重復記錄)

List<Object[]> list =  (List<Object[]>)session.createQuery(" select distinct ssex,sage from Student").list();

between...and的用法

List<Object[]> list =  (List<Object[]>)session.createQuery(" select distinct sname,ssex,sage from Student where sage between 22 and 24").list();

in 和 not in的用法

List<Student> list = session.createQuery("from Student where sdept in ('數學系','計算機系')").list();

group 和 having 和 order by
group用法:(查詢各個系的學生的平均年齡)

List<Object[]> list = session.createQuery("select avg(sage),sdept from Student group by sdept").list();

having的使用(顯示人數大於等於2的系)

List<Object[]> list = session.createQuery("select count(*),sdept from Student group by sdept having count(*) >= 2").list();

(查詢各個系女生的人數)

List<Object[]> list = session.createQuery("select count(*),sdept from Student where ssex='M' group by sdept").list();

order by用法(查詢所有學生的成績拼按照成績高低排序)

List<Object[]> list = session.createQuery("select student.sname,course.cname,grade from Studcourse order by grade DESC").list();

查詢計算機系共有多少學生
如果返回一列數據,取出數據是必須用Object,而不是Object[]

List<Object[]> list = session.createQuery("select count(*) from Student where sdept='計算機系'").list();

查詢總成績是多少

List<Object[]> list = session.createQuery("select sum(grade) from Studcourse").list();

查詢課程號為1001的課程名稱,最高分和最低分

List<Object[]> list = session.createQuery("select course.cname,min(grade),max(grade) from Studcourse where course.cid=1011").list();

查詢各科大於80分的學生的名字,科目,分數

List<Object[]> list =session.createQuery("select student.sname,course.cname,grade from Studcourse where grade > 80").list();

計算各科大於80分的的學生數量

List<Object[]> list = session.createQuery("select course.cname,count(*) from Studcourse where grade>80 group by course.cid").list();

5.HQL分頁技術

查詢所有學生成績進行高低排序並只分頁顯示。

//獲取頁數
int pageCount = Integer.parseInt(session.createQuery("select count(*) from Studcourse").uniqueResult().toString()) /3 +1;
System.out.println("一共有"+pageCount+"頁");
//開始查詢
for(int i = 0; i < pageCount; i++){
	List<Object[]> list = session.createQuery("select student.sname,course.cname,grade from Studcourse order by grade DESC").
			setFirstResult(i*3).setMaxResults(3).list();
	for(int j = 0; j < list.size(); j ++) {
		Object[] obj = list.get(j);
		System.out.println(obj[0].toString() + "  " + obj[1].toString() + " " + obj[2].toString());
	}
	System.out.println("*******第"+(i+1)+"頁**********");
}

6.參數綁定

好處:
1.可讀性高
2.效果好
3.防止sql注入漏洞

一般寫法:

List<Student> list = session.createQuery("from Student where sage = 22 and sname = '張三'").list();

參數綁定寫法:
如果我們的參數是冒號形式給出的,則可以這樣寫:

List<Student> list = session.createQuery("from Student where sage=:sage andsname=:sname").setString("sage", "22").setString("sname", "張三").list();

如果我們的參數是問號形式給出的,則可以這樣寫:

List<Student> list = session.createQuery("from Student where sage=? and sname=?").setString(0, "22").setString(1, "張三").list();

將綁定分開寫:

Query query = session.createQuery("from Student where sage=? and sname=?");
query.setInteger(0, 22);
query.setString(1, "張三");
List<Student> list = query.list();

映射文件中得到hql語句

hibernate提供了一種更加靈活的查詢方法。
把hql語句配置到對象關系映射文件

<query name="myquerytest">
    from Student
</query>

八、hibernate對象的三種關系映射

  1. one-to-one: 身份證<---->人 丈夫<--->妻子
  2. one-to-many: 部門<--->員工
  3. many-to-one:員工<--->部門
  4. many-to-many:學生<--->老師(盡量避免)
    (在實際開發過程中,如果出現了多對多的關系,我們應該盡量裝換為兩個一對多或者多對一的關系,這樣程序好控制,同時不會有冗余)

1.one-to-one

一對一兩種方式:
(1)基於主鍵的一對一
(人<--->身份證 one<--->one)

//Person.java,略去了相關的get/set方法
private Integer id;
private String name;
private IdCard idCard;
//Person.hbm.xml
<hibernate-mapping package="com.sun.hibernate.model">
  <class name="Person">
	<id name="id" type="java.lang.Integer">
		<!-- 我們手動分配id -->
		<generator class="assigned" />
	</id>
	<property name="name" type="java.lang.String">
		<column name="name" length="128" />
	</property>
	<!-- 這里配置person和idcard屬性是一對一關系 -->
	<one-to-one name="idCard"></one-to-one>
</class>
</hibernate-mapping>
//IdCard.java,略去了相關的get/set方法
private Integer id;
private Date validata;
private Person person;
//IdCard.hbm.xml
<hibernate-mapping package="com.sun.hibernate.model">
  <class name="IdCard">
	<id name="id" type="java.lang.Integer">
		<!-- 因為我們這里是基於主鍵的one-to-one, 所以我們使用外鍵策略 -->
		<generator class="foreign">
			<!-- 這里值,是指跟那個屬性ont-to-one -->
			<param name="property">person</param>
		</generator>
	</id>
	<property name= "validata" type="java.util.Date">
		<column name="validata" />
	</property>
	<!-- constrained設置為true才會使得在數據提交的時候同時提交相關的關聯關系,在此例中如果沒有IdCard表將不會有外鍵-->
	<one-to-one name="person" constrained="true" />
</class>
</hibernate-mapping>

(2)基於外鍵的一對一
(人<--->身份證 one<--->one)

//Person.java,略去了相關的get/set方法(和基於主鍵的Person.java一致)
private Integer id;
private String name;
private IdCard idCard;
//Person.hbm.xml(和基於主鍵的Person.hbm.xml一致)
<hibernate-mapping package="com.model.one2one">
	<class name="Person">
		<id name="id" type="java.lang.Integer">
			<!-- 我們手動分配id -->
			<generator class="assigned" />
		</id>
		<property name="name" type="java.lang.String">
			<column name="name" length="128" />
		</property>
		<!-- 這里配置person和idcard屬性是一對一關系 -->
		<one-to-one name="idCard"></one-to-one>
	</class>
</hibernate-mapping>
//IdCard.java,略去了相關的get/set方法(和基於主鍵的IdCard.java一致)
private Integer id;
private Date validate;
private Person person;
//IdCard.hbm.xml(注意與基於主鍵的IdCard.hbm.xml的區別)
<hibernate-mapping package="com.model.one2one">
	<class name="IdCard">
		<!-- 基於外鍵的one-one -->
		<id name="id" type="java.lang.Integer">
			<generator class="assigned" />
		</id>
		<property name="validate" type="java.util.Date">
			<column name="validate" />
		</property>
		<many-to-one name="person" unique="true" />
	</class>
</hibernate-mapping>

//測試函數
//添加一組Person/idcard
Session session = null;
Transaction ts = null;
try {
    session = MySessionFactory.getSessionFactory().openSession();
    ts = session.beginTransaction();
    Person p1 = new Person();
    p1.setId(100);
    p1.setName("小明");
    IdCard idCard = new IdCard();
    idCard.setId(2015001);//如果是基於主鍵的one-to-one關系則不用設置
    idCard.setValidate(new Date());
    idCard.setPerson(p1);
    session.save(p1);
    session.save(idCard);
    ts.commit();
} catch (Exception e) {
    e.printStackTrace();
}finally{
    if(session != null && session.isOpen()){
        session.close();
    }
}

2.one-to-many

配置文件示例
(學生<----->選課表 one<--->many)

//Student.hbm.xml配置文件
//Student.java定義Studcourse代碼:private Set<Studcourse> studcourses = new HashSet<Studcourse>(0);
<set name="studcourses" inverse="true">
    <key>
        <column name="sid" />
    </key>
    <one-to-many class="com.domain.Studcourse" />
</set>
//Studcourse.hbm.xml配置文件
//Studcourse定義Student代碼:private Student student;
<many-to-one name="student" class="com.domain.Student" fetch="select">
    <column name="sid" />
</many-to-one>

3.many-to-many

學生<--->課程
many-to-many在實際開發過程中,如果出現這種多對多的關系,我們應該盡量轉換為兩個一對多或者多對一的關系,這樣程序好控制,同時不會有冗余。
所以學生<--->課程我們轉換為學生<--->選課記錄表(many<--->one) 選課記錄表<--->課程(one<--->many)

學生表(student)

sid sname sdept
2001 李華 計科

選課表(studcourse)

idstudcourse sid cid grade
1 2001 A101 87

課程表(course)

cid cname ccredit
A101 java編程課 3
如上所示,我們使用選課表將學生<--->課程多對多的關系化解成了兩個多對一的關系。

代碼及配置

//Student.java
private Integer sid;
private String sname;
private String sdept;
private Set<Studcourse> studcourses = new HashSet<Studcourse>(0);
//Student.hbm.xml
<hibernate-mapping>
    <class name="com.domain.Student" table="student" catalog="course">
        <id name="sid" type="java.lang.Integer">
            <column name="sid" />
            <generator class="identity" />
        </id>
        <property name="sname" type="string">
            <column name="sname" length="20" not-null="true" />
        </property>
        <property name="sdept" type="string">
            <column name="sdept" length="10" not-null="true" />
        </property>
        <set name="studcourses" inverse="true">
            <key>
                <column name="sid" />
            </key>
            <one-to-many class="com.domain.Studcourse" />
        </set>
    </class>
</hibernate-mapping>

//Studcourse.java
private Integer idstudCourse;
private Course course;
private Student student;
private Integer grade;
<hibernate-mapping>
    <class name="com.domain.Studcourse" table="studcourse" catalog="course">
        <id name="idstudCourse" type="java.lang.Integer">
            <column name="idstudCourse" />
            <generator class="identity" />
        </id>
        <many-to-one name="course" class="com.domain.Course" fetch="select">
            <column name="cid" />
        </many-to-one>
        <many-to-one name="student" class="com.domain.Student" fetch="select">
            <column name="sid" />
        </many-to-one>
        <property name="grade" type="java.lang.Integer">
            <column name="grade" />
        </property>
    </class>
</hibernate-mapping>


Course.java
private Integer cid;
private String cname;
private Integer ccredit;
private Set<Studcourse> studcourses = new HashSet<Studcourse>(0);
//Course.hbm.xml
<hibernate-mapping>
    <class name="com.domain.Course" table="course" catalog="course">
        <id name="cid" type="java.lang.Integer">
            <column name="cid" />
            <generator class="identity" />
        </id>
        <property name="cname" type="string">
            <column name="cname" length="40" not-null="true" />
        </property>
        <property name="ccredit" type="java.lang.Integer">
            <column name="ccredit" />
        </property>
        <set name="studcourses" inverse="true">
            <key>
                <column name="cid" />
            </key>
            <one-to-many class="com.domain.Studcourse" />
        </set>
    </class>
</hibernate-mapping>
//Test.java
Student stu = new Student();	
stu.setSname("王寶強");
stu.setSsex("M");
stu.setSdept("表演系");
stu.setSage(32);
stu.setSaddress("河南");


Course course = new Course();
course.setCid(1016);
course.setCname("asp.net");
course.setCcredit(4);

Studcourse stucourse = new Studcourse();
stucourse.setIdstudCourse(20009);
stucourse.setStudent(stu);
stucourse.setCourse(course);
stucourse.setGrade(79);

Session session = null;
Transaction ts = null;
try {
	session = HibernateUtil.openSession();
	ts = session.beginTransaction();
	
	session.save(course);
	
	session.save(stu);	
	
	session.save(stucourse);
	
	ts.commit();
} catch (Exception e) {
	if(ts != null){
		ts.rollback();
	}
	throw new RuntimeException(e.getMessage());
}finally{
	//關閉session
	if(session != null && session.isOpen()){
		session.close();
	}
}

九、 對象的三種狀態

1. 瞬時狀態(transient)

數據庫中沒有數據與之對應,超過作用域會被JVM垃圾回收器回收,一般是new出來且且與session沒有關聯的對象。

2.持久狀態(persitent)

數據庫中有數據與之對應,與當前session有關聯,並且相關聯的session沒有關閉,事物沒有提交;持久對象狀態發生改變,在事務提交時會影響數據庫(hibernate能檢測得到)

3.托管狀態/游離狀態(datached)

數據庫中有數據與之對應,但當前沒有session與之關聯;脫管狀態發生改變時,hibernate不能檢測到。

Student stu = new Student();	//stu就是瞬時狀態
		stu.setSname("王寶強");
		stu.setSsex("M");
		stu.setSdept("表演系");
		stu.setSage(32);
		stu.setSaddress("河南");
		
		Session session = null;
		Transaction ts = null;
		try {
			session = HibernateUtil.openSession();
			ts = session.beginTransaction();
			
			session.save(stu);	
			//stu既處於session管理下,
			//同時stu被保存到數據庫中,因此stu此時是持久態
			stu.setSname("唐國強");//hibernate能檢測到,並且會提交到數據庫中去
			ts.commit();
			session.close();
			//這是stu被保存到數據庫中,沒有處於session的管理之下
			//此時stu就是脫管狀態(游離態)
			
		} catch (Exception e) {
			if(ts != null){
				ts.rollback();
			}
			throw new RuntimeException(e.getMessage());
		}finally{
		}

十、級聯操作

所謂級聯操作就是說,當你進行某個操作(添加、修改、刪除),就有hibernate自動給你完成。
比如刪除一個學生那么這個學生相應的選課表也要被刪除。
配置(配置cascade對應的屬性就可以實現相應的級聯操作)cascade:create,merge,save-update,delete,lock,refresh,evict,replicate;默認值為none,也可以設置為all
級聯操作一般在one-to-one和one-to-many中比較有用,在many-to-one和many-to-many中沒有什么意義。

<set name="studcourses" inverse="true" cascade="save-update">

十一、 其他

1. 什么是pojo類,他有什么要求?

  • pojo類和一張表對應
  • 一般放在com.XXX.domain下
  • pojo需要一個主鍵屬性(用於標示一個pojo對象)
  • 除了主鍵屬性,它還應當有其他屬性,屬性的訪問權限為private
  • 提供get/set方法
  • 它應當有一個無參構造方法(hibernate反射)
  • pojo類其實就是一個javaBean(有時也叫Data對象)

2. hibernate核心類和接口
1. configuration類
2. 讀取配置文件
3. 管理關系映射文件
4. 加載hibernate的驅動,url,用戶
5. 管理hibernate配置信息

3. hibernate.cfg.xml
4. 對象關系映射文件
5. SessionFactory接口(會話工廠)
1. 可以緩存sql語句和數據(稱為session級緩存)
2. 是一個重量級的類,因此需要保證一個數據庫有一個SessionFactory
6. 通過SessionFactory獲取Session的兩個方法
1. openSession()是獲取一個新的Session
2. getCurrentSession()獲取和當前綁定的session,換言之,在同一個線程中,我們獲取的session是同一個session。(如果希望使用getCurrentSession需要配置hibernate.cfg.xml)

<property name="current_session_context_class">thread</property>

3.如何選擇
如果在同一個線程中,保證使用同一個session,則使用getCurrentSession(),如果在同一個線程中需要使用不同的Session,則使用opentSession()
4. openSession() 和 getCurrentSession()的區別
* 通過getCurrentSession獲取的session在事務提交以后會自動關閉,通過openSession獲取的session則必須手動關閉,但是我們建議不管什么形式獲取的session都進行判斷后手動關閉。
* 如果是通過getCurrentSession()獲取session進行查詢時,也要進行事務提交。

7. 本地事務:針對一個數據庫的事物
全局事務:跨數據庫的事物(jta)

8. session接口:
主要功能和作用
1. session一個實例代表與數據庫的一次操作。(當然一次操作可以使crud組合)
2. session實例是通過SessionFactory獲取,用完需要關閉。
3. session實例是線程不同步的(不安全),因此要保證在同一線程中使用,可以用getCurrentSession()
4.session可以看做是持久化管理器,它與持久化操作相關的接口。

get() 和load()區別
1. get()方法直接返回實體類,如果找不到數據則返回null。load()會返回一個實體代理對象(當前這個對象可以自動轉化為實體對象)。但當代理對象被調用時,如果數據不存在,就會拋出org.hibernate.ObjectNotFoundException異常。
2. load先到緩存(session緩存/二級緩存)中去查,如果沒有則返回一個代理對象(不馬上到DB中去找),等后面使用這個代理對象操作的時候,才到DB中去查詢,這就是我們常說的load在默認情況下支持延遲加載(lazy--->我們可以在配置文件中關閉懶加載功能).

懶加載

簡述:當我們查詢一個對象的時候,在默認情況下返回的只是該對象普通屬性,當用戶使用哪個對象屬性是才會向數據庫中發出一次查詢,這種現象我們成為懶加載現象
禁用懶加載功能
方法一:(配置文件中進行禁用)

<class name="Student" lazy="false">

方法二:(顯示初始化,Hibernate.initizlize(代理對象))

Hibernate.initlalize(stu.getDept());

方法三:(通過過濾器openSessionview解決)
3. get先到緩存(session緩存/二級緩存)中去查,如果沒有就到DB中去查(即馬上發出sql)。總之,如果你確定DB中有這個對象就用load(),不確定就用get()(這樣效率高)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM