Student Demo(实习的第一个小小小Demo)

一、需求

使用WebService+Hibernate+Oracle完成一下这几个需求

(刚到公司实习,老大让我先自学给了几个简单项目练手)
1、能录入同学成绩;
2、获取全班成绩列表;
3、计算全班成绩平均分;
4、查询单个同学单科成绩;
5、合理设计表结构,这个也会检查。

二、建库建表

(一)数据库表的设计:使用的Oracle数据库

       学生表(STUDENT_USER)下面统称USER表:USER_ID为主键

Student Demo(实习的第一个小小小Demo)

 

 课程表(STUDENT_COURSE)下面统称COURSE表:COURSE_ID为主键

(这里为什么有英文又要中文后面设计视图的时候分析)。

Student Demo(实习的第一个小小小Demo)

 成绩表(STUDENT_GRADE)下面统称GRADE表(关联课程和学生表):

这里我用的是联合主键——(USER_ID,COURSE_ID),同时他们也是外键,分别关联USER表,COURSE表。USER_ID和USER表的约束为SET NULL 这样当我删除某条学生信息的时候,同时会删除该学生的所有信息。

Student Demo(实习的第一个小小小Demo)

(二)创建物化视图

为什么使用物化视图?(个人想法欢迎指点)

        物化视图的更新十分影响性能,但是用它来查询数据,那么可以节省很多的时间。、

        因为我觉得学生数据主要还是以查询为主,学生是没有权限去修改数据的,同时每次插入学生信息,一般就是在开学的时候,插入成绩就是在每次考试的时候,每次修改完半夜手动刷新就行了(我觉我在学校的成绩搞好几天才能查到这个原因),修改的次数比较少,所以我觉得建立一张物化视图,可以优化数据库,方便操作。

物化视图和普通视图的区别:

        普通视图其实还是使用Sql查询,每次查询还是重复查询Sql,我觉得除了方便没有其他意义(不让程序员查看其他字段信息?)具体不是很清楚。

        物化视图是直接建立一张物理表,存储在本地,等于生成了一张新的表,刷新的化一般就是手动刷新或者更改自动刷新,我这里使用的是自动刷新(主要是为了测试省事)

Student Demo(实习的第一个小小小Demo)

建立物化视图的SQl

SELECT 
			STUDENT_GRADE.USER_ID ID ,
			STUDENT_USER.USER_NAME NAME,
			STUDENT_USER.USER_SEX SEX,
			SUM(CASE STUDENT_GRADE.COURSE_ID 
					WHEN 1 THEN STUDENT_GRADE.USER_GRADE
					ELSE 0 END) LANGUAGE,	
			SUM(CASE STUDENT_GRADE.COURSE_ID 
					WHEN 2 THEN STUDENT_GRADE.USER_GRADE
					ELSE 0 END) ENGLISH,
			SUM(CASE STUDENT_GRADE.COURSE_ID 
					WHEN 3 THEN STUDENT_GRADE.USER_GRADE
					ELSE 0 END) MATHEMATICS,
			SUM(STUDENT_GRADE.USER_GRADE) TOTAL
		FROM
			STUDENT_USER JOIN STUDENT_GRADE
		ON
			STUDENT_USER.USER_ID = STUDENT_GRADE.USER_ID
GROUP BY STUDENT_USER.USER_NAME,
			   STUDENT_GRADE.USER_ID,
				 STUDENT_USER.USER_SEX

        至于之前为什么课程表中需要有中文,英文就是这个物化视图中的字段,中文的化到时候代码返回,会用到,同时可以用中文关联去查询英文,在去查找需要的字段。

 三、代码实现

(一)导入依赖

 <dependencies>

    <!--  启动业务用的包                                                                     -->
    <!--    Oracle 驱动-->
    <dependency>
      <groupId>com.oracle</groupId>
      <artifactId>ojdbc6</artifactId>
      <version>11.2.0.2.0</version>
    </dependency>

    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.4.1.Final</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
    </dependency>

<!--    ws依赖 -->
    <dependency>
      <groupId>org.apache.cxf</groupId>
      <artifactId>cxf-rt-frontend-jaxws</artifactId>
      <version>3.0.1</version>
    </dependency>

    <!-- 日志引入  -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.12</version>
    </dependency>

    <!-- spring 核心 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <!-- spring web集成 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <!-- spring 整合junit  -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.2.4.RELEASE</version>
    </dependency>
    <!-- junit 开发包 -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.2</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
          <showWarnings>true</showWarnings>
        </configuration>
      </plugin>
      <!-- 运行tomcat7方法:tomcat7:run -->
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <!-- 指定端口 -->
          <port>8080</port>
          <!-- 请求路径 -->
          <path>/</path>
        </configuration>
      </plugin>
    </plugins>
  </build>

  (二)   文件配置

配置连接HIbernate

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>
    <session-factory>
        <!--        数据源配置-->
        <property name="connection.username">LUNA_MCS_SXS</property>
        <property name="connection.password">ewell</property>
        <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
        <property name="connection.url">jdbc:oracle:thin:@//192.168.(**).25:1521/EWELL</property>
        <!--    c3po-->
        <property name="hibernate.c3p0.acquire_increment">10</property>
        <property name="hibernate.c3p0.idle_test_period">10000</property>
        <property name="hibernate.c3p0.timeout">5000</property>
        <property name="hibernate.c3p0.max_size">30</property>
        <property name="hibernate.c3p0.min_size">5</property>
        <property name="hibernate.c3p0.max_statements">10</property>

<!--        设置方言-->
        <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
        <!--        答应SQL语句-->
        <property name="show_sql">true</property>
        <!--        格式化SQL-->
        <property name="format_sql">true</property>
        <!-- 配置在输出的SQL语句前面添加提示信息 -->
        <property name="use_sql_comments">true</property>
        <!--    注册实体关系文件-->
<!--        <mapping resource="dao/xml/StudentCourse.hbm.xml"></mapping>-->
        <mapping class="org.example.entity.StudentCourse"></mapping>
        <mapping class="org.example.entity.StudentUser"></mapping>
        <mapping class="org.example.entity.StudentGrade"></mapping>
        <mapping class="org.example.entity.MVStudent"></mapping>

    </session-factory>
</hibernate-configuration>

 配置web.xml文件

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>

    <display-name>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>cxfservlet</servlet-name>
        <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>cxfservlet</servlet-name>
        <url-pattern>/ws/*</url-pattern>
    </servlet-mapping>
    <!--2.spring容器配置-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
</web-app>

配置 applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cxf="http://cxf.apache.org/core"
       xmlns:jaxws="http://cxf.apache.org/jaxws"
       xmlns:jaxrs="http://cxf.apache.org/jaxrs"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://cxf.apache.org/core
        http://cxf.apache.org/schemas/core.xsd
        http://cxf.apache.org/jaxws
        http://cxf.apache.org/schemas/jaxws.xsd
        http://cxf.apache.org/jaxrs
        http://cxf.apache.org/schemas/jaxrs.xsd">

        <!--
            Spring整合cxf发布基于restful风格服务,关键点:
            1. 服务地址
            2. 服务类
            服务完整访问地址:http://localhost:8080/ws/serviceWs

        -->
    <jaxws:server address="/serviceWs">
        <jaxws:serviceBean>
            <bean class="org.example.service.impl.StudentServiceImpl"></bean>
        </jaxws:serviceBean>
    </jaxws:server>

</beans>

(三)创建关联表(没啥好说的,和视图还有表关联)

关联GRADE表(其他表基本都一样的)

@Data
@Accessors(chain = true)
@Entity
@Table(name = "STUDENT_GRADE")
public class StudentGrade implements Serializable {
    @Id
    @Column(name = "USER_ID")
    private Integer userID;
    @Id
    @Column(name = "COURSE_ID")
    private Integer courseID;
    @Column(name = "USER_GRADE")
    private Integer grade;
}

(四)需求实现

1.修改或者插入学生成绩:

        思路的话用个对象接受学生信息,封装到映射学生表的类里面去,然后再把AllCourses对象里面的成绩拆离出来,插入到成绩表中。(挺简单的)

   @WebMethod(operationName = "ModifyTheStudent")
    public void setGrade(
            @WebParam(name = "StudentInformation") StudentInformation studentInformation) {
        //先拿到这个学生
        StudentUser studentUser = new StudentUser();
        studentUser.setId(studentInformation.getId());
        studentUser.setName(studentInformation.getName());
        studentUser.setSex(studentInformation.getSex());
        //语文成绩
        StudentGrade languageGrade = new StudentGrade();
        languageGrade.setUserID(studentInformation.getId())//学生学号
                .setCourseID(1)//课程id
                .setGrade(studentInformation.getGrades().getLanguage());//课程成绩
        //英语成绩
        StudentGrade englishGrade = new StudentGrade();
        englishGrade.setUserID(studentInformation.getId())
                .setCourseID(2)
                .setGrade(studentInformation.getGrades().getEnglish());
        //数学成绩
        StudentGrade mathematicsGrade = new StudentGrade();
        mathematicsGrade.setUserID(studentInformation.getId())
                .setCourseID(3)
                .setGrade(studentInformation.getGrades().getMathematics());
        session.merge(studentUser);
        System.out.println(studentUser);
        session.saveOrUpdate(languageGrade);
        System.out.println(languageGrade);
        session.saveOrUpdate(englishGrade);
        System.out.println(englishGrade);
        session.saveOrUpdate(mathematicsGrade);
        System.out.println(mathematicsGrade);
        session.beginTransaction().commit();
        //一开始不清除缓存是无法修改的,会报:(A different object with the same identifier value was already associated with the session :
        // [org.example.entity.StudentUser#65)的错误,是因为session中有原先这个id对象的缓存,相同id其他不同的对象无法加入,所以需要清楚一下缓存
        session.clear();
    }

首先我用一个StudentInformation 对象来接受传入的参数 :

StudentInformation : {

private Integer id; //学生的学号
private String name; //学生的名字
private String sex; //学生的性别
private AllCourses grades : {
        private Integer language;  //学生的语文成绩
        private Integer english;   //学生的英语成绩
        private Integer mathematics; //学生的数学成绩
    };
}

        一开始我是用一个Map集合接受学生的成绩的(其实后面很多返回值一开始都用了map),但是发现WebService好像不太建议使用map(有可能是我学艺不精,等以后慢慢学习),于是我该用对象接受。

        然后session(因为没清除缓存)这边我也遇见了问题:见这篇博客

2.获取所有学生的成绩

思路:这个就更简单了,直接获取物化视图遍历出来,也没啥好说的

    @WebMethod(operationName = "GetStudentGrades")
    public @WebResult(name = "StudentGrades") List<MVStudent> getGrade() {
        String hql = "from MVStudent ";
        return session.createQuery(hql).list();
    }

3.获取平均成绩

                因为老大只告诉我说要获取平均成绩,我也不知道获取什么的平均成绩,于是我干脆通过输入课程表中的课程编号获取这门课的平均成绩。 

        然后的话如果要获取总平均成绩的话,就输入课程表中没有的ID(其实也可以增加一个特殊ID是这个特殊ID就平均成绩)这样的话每次新增课程,课程表中ID也会相应的增加,依旧可以获取对应的课程成绩。

        判断的话我就直接拿他给我的id去查,查出来的list集合为空的话,那么就返回平均值。

  @WebMethod(operationName = "GetCourseAverage")
    public @WebResult(name = "CourseAverage")
    CourseScore getAverage(
            @WebParam(name = "CourseID") Integer courseId) {
        CourseScore average = new CourseScore();
        Integer vag = 0;
            //查询对方想要什么科目,取出这门课的名字和课程字段
            String hql = "from StudentCourse where id = ?1";
            //集合为空说明没查到对应课程,返回平均值
            List list1 = session.createQuery(hql)
                    .setParameter(1, courseId).list();
            if (list1.size() == 0){
                List<MVStudent> grade = getGrade();
                for (MVStudent mvStudent : grade) {
                    vag = vag + mvStudent.getTotal() / grade.size();
                }
                average.setCourse("总平均分").setVag(vag);
                return average;
            }
            StudentCourse course = (StudentCourse) list1.get(0);
            System.out.println(course);
            String sql = "select * from MV_STUDENT";
            List<Object> list = session.createNativeQuery(sql).addScalar(course.getCourseName()).list();
            System.out.println(list);
            for (Object o : list) {
                int i = Integer.parseInt(o.toString());
                vag = vag + i / list.size();
            }
            average.setCourse(course.getName()).setVag(vag);
        return average;
    }

遇见问题:

        这边遇见一个很尴尬的问题,主要感觉还是基础不牢(地动山摇啊)Hibernate 返回类型转Integer

4.获取某门课的成绩

这个也很简单,就是直接拿ID去物化视图里面查,然后取出自己想要的东西

    @WebMethod(operationName = "GetStudentGrade")
    public @WebResult(name = "StudentGrade")
    AllCourses getCourseGrade(
            @WebParam(name = "StudentID") Integer id) {
        AllCourses courseGrade = new AllCourses();
        String hql = "from MVStudent where id= ?1 ";
        Query query = UtilSession.getQuery().createQuery(hql);
        query.setParameter(1, id);
        List<MVStudent> list = query.list();
        MVStudent mvStudent = list.get(0);
        courseGrade.setLanguage(mvStudent.getLanguage())
                .setEnglish(mvStudent.getEnglish())
                .setMathematics(mvStudent.getMathematics());
        return courseGrade;
    }

总结:

1.表设计其他想法

        我一开始有另外一个想法,因为如果所有成绩放在一张表里面的话,一旦课程过多或者学生过多的话会导致成绩表特别的大和冗余,查询和遍历就很浪费时间。

        于是我打算一门课程一张表。课程表里面拿一个字段出来存储这门课程所在的表(其实也不用),这样子每次增加新的课程的话新增一张表就好了。我总结下自认为的优缺点

             优点:1、当数据量很大的时候查询速度快(比如大学里面大量数据)。2、插入方便,如果某个学生的某门课程需要更改(或者需要增加这门课程的分数),去对应的表里面修改就行了(而且还可以用多线程的方式并发插入,操作不同表的话,相对比多线程操作一张表要安全的多)。3、主要是我感觉这样子整个数据库的结构就清晰明了,不至于成绩表像锅大杂烩。

              缺点:1、数据库表过多?(空间换时间?)2、操作繁琐(每个学生可能因为选的课不一样,导致查询繁琐——我觉得可以学生表里面可以使用一个字段,去存储自己选修了那些课解决这个问题,所以我觉得这不是问题)?3.其他问题欢迎大家指点一下,菜鸟阶段很多不懂。

Student Demo(实习的第一个小小小Demo)

 

2.杂谈随笔      

        写这个东西大概花了我两天半左右,需要使用hibernate,Oracle,WebService(学习)

        因为这些东西都是刚学的,而且就学了一下子,了解的比较浅,所以最大的问题反而是依赖的选择(因为我有时候根本不知道有这个依赖),环境的搭建(有时候明明照着网上操作,总会出莫名其妙的问题),因为技术比较老,网上资料都是 1*年甚至0*年的,很多东西都淘汰了。

                1. 比如HIbernate和Oracle搭建,数据库驱动一开始需要去下载,后面想了想,公司Maven仓库里面肯定有配套的。下下来发现驱动好像HIbernate版本出问题,又去改了一下,搞了半天。然后很多配置也是0几年的,去网上找,很多配置都淘汰了,后面又找到官网去了

                2.反正配置方面乱七八糟的问题(我想这可能就是架构师为啥工资这么高的问题,哈哈)每次一个项目从0到有最难的就是项目配置搭建

        写代码业务其实就花了半天左右,这半天里面有一小半时间还是在解决上面说到的两个问题。感觉业务挺简单的。

上一篇:Linux 笔记 03 Vim 编辑器与 Shell 命令脚本


下一篇:Shell编程之条件语句