发表于: 2018-03-13 22:59:01

2 729


今天完成的事情:(一定要写非常细致的内容,比如说学会了盒子模型,了解了Margin)

一、继续昨天关于创建mapper

在Mybatis中,由于mapper接口的存在,所以不用写实现类,就可以直接操作数据库

在昨天的基础上,步骤如下

1.先看结构表

2.创建具体类Person

public class Person{
private int id;
private String name ;
private int age ;
private String personID ;
public  Person(){}
public Person(int id,String name, int age, String personID) {   //如果没有此构造方法,updatePerson方法就不能直接                                                输入信息,需要使用set方法一个个输入
this.id = id;
this.name = name;
this.age = age;
this.personID = personID;
}
public Person(String name, int age, String personID) {     //如果没有此构造方法,addPerson方法就不能直接输入信                                              息需要使用set方法一个个输进去
this.name = name;
this.age = age;
this.personID = personID;
}
public int getId() {
return id;
}
public void setId(int id) {                //其余get/set方法省略
this.id = id;
}
public String toString() {
return "Person{"+"id="+id+",name="+name+",age="+age+",personID="+personID+"}";
}}


3.创建Mapper接口类

import model.Person;
public interface PersonMapper {
void addPerson(Person person);
void deletePerson(int id);
void updatePerson(Person person);
Person getPerson(int id);
}

注意点①:Mapper接口方法名要与后面设置的PersonMapper.xml中的每个操作sql的id同名。

          ②:Mapper接口的输入参数类型要和PersonMapper.xml中对应语句的parameterType类型相同。

          ③:Mapper接口的返回参数类型要和PersonMapper.xml中对应语句的resultType类型相同.

4.以上述Mapper中的方法设置PersonMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.PersonMapper">
<insert id="addPerson" parameterType="Person" >
insert into person1 (name,age,personID)values (#{name},#{age},#{personID})
</insert>
<select id="getPerson" parameterType="int" resultType="Person">
select * from person1 where id=#{id}
</select>
<delete id="deletePerson" parameterType="int" >
delete from person1 where id= #{id}
</delete>
<update id="updatePerson" parameterType="Person" >
update person1 set name=#{name},age=#{age},personID=#{personID} where id=#{id}
</update>
</mapper>

注意:namespace一定要写包名.对应的接口名,即上面的mapper.PersonMapper,可以在项目结构中看到。

5.配置mybatis-config.xml中的对应mapper文件,因为之前添加过一个person.xml,所以这次只需要在下面再添加一个PersonMapper.xml,其余参数不变

<mappers>
<mapper resource="mappers/PersonMappers.xml"/>
<mapper resource="mappers/Person.xml"/>
</mappers>

其中写法和上面的namespace一样,包名.文件名

6.因为在前面的PersonTest中每次操作前都要进行连接配置文件,创建会话工厂,创建会话,打开连接等操作很麻烦,所以将这些放到一个工具类中封装起来,需要时调用方法即可

public class SqlSessionUtil {
public static SqlSession getSqlsession() throws Exception{
String resource="mybatis-config.xml";
InputStream inputStream= Resources.getResourceAsStream(resource);
SqlSessionFactory sessionFactory=new SqlSessionFactoryBuilder().build(inputStream) ;
SqlSession session=sessionFactory.openSession(true);//设置为true后就不用手动提交事务了
       return  session;
}}

如上,这四步在测试时就可以使用getSqlsession()来调用了,注意,openSession后面是可以输入true的,这样每次操作完就可以不用session.commit来手动提交了。

7.创建测试类

首先右键TEST文件夹,MAKE DIRECTORY AS选择TEST SOURCE ROOT将其变为测试文件夹,然后在PersonMapper界面按ctrl+shift+t,创建测试类,具体界面的各项功能昨天贴了,选择JUnit4,选择全部功能,创建PersonMapperTest

public class PersonMapperTest {

@Test            //每一个测试方法写完可以选中@Test然后运行,此时系统只会运行一个方法
   public void addPerson() throws Exception {             //注意需要throws Exception否则会报错
       SqlSession session= SqlSessionUtil.getSqlsession();
       PersonMapper personMapper=session.getMapper(PersonMapper.class);
       Person p=new Person("wangwu",25,"20111111");
       personMapper.addPerson(p);
       session.close();          //这里其实我也不知道需不需要关闭,但是保险起见还是带上,session.commit();就不需要了
   }

@Test
   public void deletePerson() throws Exception {
       SqlSession session= SqlSessionUtil.getSqlsession();
       PersonMapper personMapper=session.getMapper(PersonMapper.class);
       personMapper.deletePerson(1510);
       session.close();
   }
@Test
   public void updatePerson() throws Exception {
       SqlSession session= SqlSessionUtil.getSqlsession();
       PersonMapper personMapper=session.getMapper(PersonMapper.class);
       Person p=new Person(1537,"niusisi",25,"20177777");
//若这里不设置personID则结果里此栏为空而不是不改

       personMapper.updatePerson(p);

           }

@Test         
   public void getPerson() throws Exception {          //注意这里并不需要有返回参数,因为测试是不会有数据返回的
       SqlSession session= SqlSessionUtil.getSqlsession();
       PersonMapper personMapper=session.getMapper(PersonMapper.class);
       System.out.println( personMapper.getPerson(1417));
       session.close();
   }}

因为我这里将构建工厂等步骤放进了工具类中,只需要在@test中调用即可

可以看到,只有Mapper接口,并没有实现类,调用方法时,也是通过创建一个接口对象,直接调用方法,而方法则储存在xml中(其实是使用了java动态代理实现接口,但是好像并不容易理解)

具体步骤:

①通过基本配置文件mybatis-config.xml获取到SqlSessionFactory对象

②通过SqlSessionFactory对象获取到SqlSession对象session

③使用SqlSession提供的getMapper()方法获取到Mapper接口的实例对象.(使用接口的.class文件获取,其实是获取了一个由jdk动态代理生成的代理类)

④之后就可以通过Mybatis生成的这个实例对象操作接口中的方法.

8.加入搜索整个表的信息,前两个中返回值和输入参数类型要对应,和第三个无关

List<Person> listPerson();
<select id="listPerson" resultType="Person">
select * from person1
</select>
@Test
public void listPerson()throws Exception{
SqlSession session= SqlSessionUtil.getSqlsession();
PersonMapper personMapper=session.getMapper(PersonMapper.class);
List<Person> ps=personMapper.listPerson();
for(Person p1:ps){
System.out.printf("%d\t%s\t%d\t%s%n",p1.getId(),p1.getName(),p1.getAge(),p1.getPersonID());
}
session.close();
}

 其实,本来搜索的标签都是select,而在昨天的Test可以发现在搜索单条信息时输入的命令是selectone,而在搜索的信息是集合时,则要使用selectlist,但是在mapper中,其根据上边接口方法返回值 类型来决定 是调用 selectOne还是selectList,如果返回的是单个对象,动态代理调用selectOne(),如果返回的是集合对象,动态代理调用selectList()

9.添加使用模糊搜索姓名的方式输出信息

List<Person> listPersonByName(String str);      //对比上一个就是方法中带有参数
<select id="listPersonByName"  parameterType="string" resultType="Person">
select * from person1 where name like concat('%',#{0},'%')
</select>
@Test
public void listPersonByName()throws Exception{
SqlSession session= SqlSessionUtil.getSqlsession();
PersonMapper personMapper=session.getMapper(PersonMapper.class);
List<Person> ps=personMapper.listPersonByName("lisi");
for(Person p1:ps){
System.out.printf("%d\t%s\t%d\t%s%n",p1.getId(),p1.getName(),p1.getAge(),p1.getPersonID());
}
session.close();
}

10.当测试方法多了之后会发现,每次前两句都是重复的,此时可以使用@before方法,将其放在before的setup()方法中,不过得先将session和personMapper定义为成员变量

修改后如下

public class PersonMapperTest {
private SqlSession session;
private PersonMapper personMapper;
@Before
   public void setup() throws Exception{
session= SqlSessionUtil.getSqlsession();
personMapper=session.getMapper(PersonMapper.class);
}
@Test
   public void addPerson() {
Person p=new Person("wangwu",25,"20111111");
personMapper.addPerson(p);
session.close();
}

11.添加根据姓名和id进行查找

List<Person> listPersonByIdAndName(Map map);

<select id="listPersonByIdAndName" parameterType="map" resultType="Person">
select * from person1 where id> #{id} and name like concat('%',#{name},'%')
</select>
public void listPersonByIdAndName(){
Map<String,Object> parms=new HashMap<>();
parms.put("id",1411);
parms.put("name","lisi");
List<Person> ps= personMapper.listPersonByIdAndName(parms);
for(Person p1:ps){
System.out.printf("%d\t%s\t%d\t%s%n",p1.getId(),p1.getName(),p1.getAge(),p1.getPersonID());
}
session.close();

12.if标签

可以将不同限定条件的sql语句合成一句,比如listPerson和listPersonByName,其sql语句中利用了一句判断语句,判断输入参数中是否有name,如果有就执行模糊搜索,如果没有就执行全部搜索,其实可以理解为没有name时其执行的是没有限定条件的name的模糊搜索

List<Person> listPerson(Map map);

<select id="listPerson" parameterType="map" resultType="Person">
select * from person1
<if test="name!=null">
where name like concat('%',#{name},'%')
</if>
</select>

@Test
public void listPerson(){
Map<String,Object> parms=new HashMap<>();
// parms.put("name","wang");
   List<Person> ps=personMapper.listPerson(parms);
for(Person p1:ps){
System.out.printf("%d\t%s\t%d\t%s%n",p1.getId(),p1.getName(),p1.getAge(),p1.getPersonID());
}
session.close();
}

可以看到,当对map对象的name属性使用Put方法赋值后,可以形成按条件查找,如果不对其进行赋值,则是全局查找,因为name属性为空,系统默认输出所有结果

同理,也可对其进行适当变形,将if标签中间的内容改为<if test="id!=null">  where id>#{id} </if>则可以变化为根据id范围来查找id大于某一值的所有结果,只需在put方法中输入需要的id即可,但是却不能直接将其加上来判断Id和Name两个条件限定下的查找,因为如果两个都不为空语句是通的情况下其中前面那一个条件是Null,后面的语句就会存在语法错误。

可以说if标签在某些时候是可以减轻录入的sql的statement的,但是在实际操作起来会发现作用比较局限,因为原本的查询所有是不需要输入参数的,现在我也必须输入参数才能执行原本不需要输入参数的操作。

13.where标签

针对上面的不能同时按照Id和name来查找的情况,可以利用where标签解决。

List<Person> listPerson(Map map);
<select id="listPerson" parameterType="map" resultType="Person">
select * from person1
<where>
<if test="name!=null">
AND name like concat('%',#{name},'%')                //会自动忽略第一个成立的条件前面的and或者or
</if>
<if test="id!=null and id!=0">
AND id>#{id}
</if>
</where>
</select>
@Test
public void listPerson(){
Map<String,Object> parms=new HashMap<>();
//parms.put("name","wang");                           
  // parms.put("id",1538);
   List<Person> ps=personMapper.listPerson(parms);
for(Person p1:ps){
System.out.printf("%d\t%s\t%d\t%s%n",p1.getId(),p1.getName(),p1.getAge(),p1.getPersonID());
}
session.close();
}

使用where标签时,若其中某个条件不成立,它会自动将statement中的and和or去掉,就能组成连贯的sql语句了,利用此方法,可以只用一个listPerson就实现之前很多listPersonByXXAndXX的功能,并且可以随意组合,提升了它的局限性

14.set标签

与where标签类似,只不过是解决在update数据时出现空字段的问题

void updatePerson(Person person);
<update id="updatePerson" parameterType="Person" >
update person1
<set>
<if test="name!=null">name=#{name},</if>              //注意非最后一条的{}后面需要有逗号,如果少了就会报错
<if test="age!=null">age=#{age},</if>               //和where标签一样,会自动忽略最后一个条件最后的逗号
<if test="personID!=null">personID=#{personID}</if>
</set>
where id=#{id}
</update>
@Test
public void updatePerson() {

Person p=new Person();
p.setName("wangqi");                    //此时若name参数不设置,则姓名不会改变
 // p.setAge(20);                     //此时若不录入age,age会自动变为0,所以可以考虑将其设置为String
//   p.setPersonID("2012222221");       //原方法若这里不设置personID则结果里此栏为null而不是不改
   p.setId(1538);
personMapper.updatePerson(p);
session.close();
}

可以看出,相比之前的不设置,最大区别就是只设置其中几个参数时,原方法中类型为String的参数会自动赋值null,就是说本来不想修改姓名,用原方法的话姓名栏会修改为Null,但是用Set标签之后则不会修改,例外是age属性,在不设置的情况下也会自动归0,而不是预想中的不修改,所以如果也想不修改,只能将age从int变为String了。

15.choose标签

由于sql中没有if else的逻辑判断语句,所以在执行此逻辑时可以使用choose标签来表达一种情况未发生时则执行另外一种

 <select id="listProduct" resultType="Product">
              SELECT * FROM product_
              <where>
                <choose>
                  <when test="name != null">
                    and name like concat('%',#{name},'%')
                  </when>          
                  <when test="price !=null and price != 0">
                    and price > #{price}
                  </when>                
                  <otherwise>
                    and id >1
                  </otherwise>
                </choose>
              </where>
        </select>

基本的xml语句如图,可以看到使用了where,choose,when,otherwise的结构

16.foreach标签

用来实现按指定条件查找,比如找三个具体Id的数据并返回

List<Person> listPersonById(List list);
<select id="listPersonById" parameterType="list" resultType="Person">
SELECT * FROM person1
WHERE ID in
<foreach item="item" index="index" collection="list"
            open="(" separator="," close=")">
#{item}
</foreach>
</select>
@Test
public void listPersonById(){
List<Integer> ids=new ArrayList();
ids.add(1413);
ids.add(1535);
ids.add(1540);
List<Person> ps=personMapper.listPersonById(ids);
for(Person p1:ps){
System.out.printf("%d\t%s\t%d\t%s%n",p1.getId(),p1.getName(),p1.getAge(),p1.getPersonID());
}
session.close();
}

可以看出此标签可以实现多个指定条件的搜索

释义: 

collection :collection属性的值有三个分别是list、array、map三种,分别对应的参数类型为:List、数组、map集合,上面传的参数为List,所以值为list  item : 表示在迭代过程中每一个元素的别名     

index :表示在迭代过程中每次迭代到的位置(下标)     

open :前缀     

close :后缀     

separator :分隔符,表示迭代时每个元素之间以什么分隔

17.将xml形式的CRUD修改为注解方式

使用Mapper接口时,除了在PersonMapper.xml中储存sql语句外,还可以使用注解的方式直接在PersonMapper中直接以注解的形式将sql语句加上去,

 @Insert(" insert into person1 ( name ) values (#{name}) "
    public void add(Person person); 

此时,就需要将mybatis-config.xml中的映射位置改为

<mappers>
        <mapper resource="mapper.PersonMapper.xml"/>
        <mapper class="mapper.PersonMapper"/> 
    </mappers>

除此之外,在测试类中的操作则基本不变,可以看出,此方法避免了配置PersonMapper.xml文件,而是将statement直接以注解形式加在对应方法上,如果只进行比较简单的CRUD操作的话,是比较方便的,但是如果涉及比较复杂的sql操作,则还是配置xml文件比较好一点。

二、关于JUnit

使用后发现,还是比较方便的主要体现在这几方面:

①可以一键生成需要的测试方法的躯干

②可以设置before,after将测试主体中重复操作取出来

③可以单独测试某个方法而不需要整个都运行

④测试代码和程序主体代码分开,在打包时测试代码是不会打包进去的

三、耦合性,内聚性

1.内聚性,又称块内联系。指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量。

内聚性是对一个模块内部各个组成元素之间相互结合的紧密程度的度量指标。模块中组成元素结合的越紧密,模块的内聚性就越高,模块的独立性也就越高。理想的内聚性要求模块的功能应明确、单一,即一个模块只做一件事情。模块的内聚性和耦合性是两个相互对立且又密切相关的概念。

2.耦合性也叫块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块之间越独立则越差,模块间耦合的高低取决于模块间接口的复杂性,调用的方式以及传递的信息。

形象的说,就是要将代码写的和电脑一样,主类就是电脑的主机箱,当程序需要实现什么功能的时候只需要加其他的类引入接口,就像电脑上的usb接口。

3.内聚

内聚有如下种类,他们之间的内聚性由弱到强排列为偶然内聚、逻辑内聚、时间内聚、过程内聚、通信内聚、顺序内聚、功能内聚。

(低——高)①偶然内聚指一个模块内的各处理元素之间没有任何联系。②逻辑内聚指模块内执行几个逻辑上相似的功能,通过参数确定该模块完成哪一个功能。③时间内聚:把需要同时执行的动作组合在一起形成的模块为时间内聚模块。④通信内聚指模块内所有处理元素都在同一个数据结构上操作(有时称之为信息内聚),或者指各处理使用相同的输入数据或者产生相同的输出数据。⑤顺序内聚指一个模块中各个处理元素都密切相关于同一功能且必须顺序执行,前一功能元素输出就是下一功能元素的输入。⑥功能内聚:这是最强的内聚,指模块内所有元素共同完成一个功能,缺一不可。

4.耦合

耦合可以分为下列几种,他们之间的耦合度由高到低排列为内容耦合、公共耦合、外部耦合、控制耦合、标记耦合、数据耦合、非直接耦合。

(低——高); ①无直接耦合;数据耦合指两个模块之间有调用关系,传递的是简单的数据值,相当于高级语言的值传递;标记耦合指两个模块之间传递的是数据结构,如高级语言中的数组名、记录名、文件名等这些名字即标记,其实传递的是这个数据结构的地址; 控制耦合指一个模块调用另一个模块时,传递的是控制变量(如开关、标志等),被调模块通过该控制变量的值有选择地执行块内某一功能。; 公共耦合指通过一个公共数据环境相互作用的那些模块间的耦合。公共耦合的复杂程序随耦合模块的个数增加而增加。内容耦合:这是最高程度的耦合,也是最差的耦合。

5.耦合性与内聚性是模块独立性的两个定性标准,将软件系统划分模块时,尽量做到高内聚低耦合,提高模块的独立性,为设计高质量的软件结构奠定基础

明天计划的事情:(一定要写非常细致的内容)

明天准备开始看Spring,顺便多使用Junit

 遇到的问题:(遇到什么困难,怎么解决的)

对于今天多次出现的List和map有点混了,不太清楚什么时候该用List,什么时候该用Map了,查了很多资料感觉讲的有点难懂,明天再好好研究一下

 收获:(通过今天的学习,学到了什么知识)

了解了Mapper接口的用法和动态sql的一些写法


返回列表 返回列表
评论

    分享到