56..java基础——零基础入门之Mybatis进阶

版权声明:版权归零零天所有,若有转载请注明出处。 https://blog.csdn.net/qq_39188039/article/details/86620491

一对一

如何配置一对一关联映射
注意,Mybatis设计中有一处缺陷,就是如果配置了关联关系,则resultMap中,要配置全所有的映射关联,否则不会封装数据,为null值
javabean代码:

public class User {
 
private String id;
private String name;
private int age;
private String address;
private UserInfo userInfo;

……get set方法
Xml代码:

<!--利用resultMap实现关联关系 -->
<resultMap type="pojo.User" id="userRM">
 
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="address" column="address"/>
<!-- 配置User和UserInfo的一对一 -->
<association property="userInfo" javaType="pojo.UserInfo">
<!-- 配置UserInfo的主键关联 -->
<id property="id" column="id"/>
<!-- 配置UserInfo的属性关联 -->
<result property="name" column="name"/>
<result property="job" column="job"/>
<result property="hobbit" column="hobbit"/>
</association>
 
</resultMap>
 
<!--关联查询,一对一  -->
<select id="findOneToOne" resultMap="userRM">
select * from user_c LEFT JOIN user_info on user_c.id=user_info.id
</select>

注意:Mybatis同名字段的bug
引发原因:Mybatis是根据反射机制来把结果集数据封装到javabean里的,当做关联的时候,比如先查的是user_c的表,有一个name列名,找到并封装到User的name属性里,然后再查User_info,发现有也有一个name列名,Mybatis就分不清了,就直接把User的name数据封装到User_info的name数据里了。这就是Mybatis的同名字段问题。
怎么避免Mybatis的同名字段问题?
核心思想:让User和User_info的结果集里的列名不一致。
Xml代码:

<!--利用resultMap实现关联关系 -->
<resultMap type="pojo.User" id="userRM">
 
<id property="id" column="userid"/>
<result property="name" column="username"/>
<result property="age" column="age"/>
<result property="address" column="address"/>
<!-- 配置User和UserInfo的一对一 -->
<association property="userInfo" javaType="pojo.UserInfo">
<!-- 配置UserInfo的主键关联 -->
<id property="id" column="userinfoid"/>
<!-- 配置UserInfo的属性关联 -->
<result property="name" column="userinfoname"/>
<result property="job" column="job"/>
<result property="hobbit" column="hobbit"/>
</association>
 
</resultMap>
 
<!--关联查询,一对一  -->
<select id="findOneToOne" resultMap="userRM">
select u.id as userid,u.name as username,u.age,u.address,
i.id as userinfoid,i.name as userinfoname,i.job,i.hobbit from
(select * from user_c)u LEFT JOIN
(select * from user_info) i on u.id=i.id
</select>

一对多


如何配置一对多关联映射?
javabean代码:

public class Dept {
 
private String deptId;
private String deptName;
private List<User> users;

Xml代码:

<!-- 2.一对多 -->
<resultMap type="pojo.Dept" id="deptRM">
<id property="deptId" column="dept_id"/>
<result property="deptName" column="dept_name"/>
 
<!-- 配置User和Dept的一对多 -->
<collection property="users" ofType="pojo.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="address" column="address"/>
 
</collection>
</resultMap>
 
<select id="findOneToMany" resultMap="deptRM">
select * from user_c,dept where user_c.dept_id=dept.dept_id
</select>

知识点:
1.用collection配置多的一方,本例中是User,注意:ofType和Collection是固定搭配

持久层代码

public void testFindOneToMany(){
SqlSession session=factory.openSession();
List<Dept> list=session.selectList("pojo.UserMapper.findOneToMany");
for(Dept d:list)System.out.println(d);
}

知识点:
1.因为我们用的resultMap是dept的映射,所以查询结果是List,也就是说,必须通过Dept来查User的信息。
作业:对于一对多,如何通过User来查Dept的信息?如何配置?

多级关联+Extends


部门里有多个用户,每个用户有用户信息,怎么配置多级关联?
Xml代码:

<!-- 3.配置多级关联 -->
<resultMap type="pojo.Dept" id="multiRM">
<id property="deptId" column="dept_id"/>
<result property="deptName" column="dept_name"/>
<collection property="users" ofType="pojo.User" >
<id property="id" column="userid"/>
<result property="name" column="username"/>
<result property="age" column="age"/>
<result property="address" column="address"/>
<association property="userInfo" javaType="pojo.UserInfo">
<id property="id" column="userinfoid"/>
<!-- 配置UserInfo的属性关联 -->
<result property="name" column="userinfoname"/>
<result property="job" column="job"/>
<result property="hobbit" column="hobbit"/>
</association>
</collection>
 
</resultMap>

配置思路:
一级一级的来配,通过Dept先配一对多,然后通过User配置一对一
持久层代码:

public void testMulti(){
SqlSession session=factory.openSession();
List<Dept> list=session.selectList("pojo.UserMapper.multiRM");
for(Dept d:list)System.out.println(d);
}

自动生成代码工具


为什么要学习这个工具?
在实际项目中,表的字段非常多,手动在映射文件写字段或是建立javabean都是不现实的,这个工具的作用:你指定数据库的一张表,利用这个工具就能自动生成javabean和写好的映射文件。

使用步骤:
1.在elicpse安装这个工具的插件
2.引入两个配置文件(一个是properties,一个是xml)
2.配置一些参数,比如和数据库的连接,指定哪张表,比如生成的javabean和映射文件放在哪个包下等
3.利用工具一键生成
知识点:
1.如何安装插件
将features和plugins都扔到eclipse—dropins的文件夹下,然后重启eclipse

2.如何验证是否安装成功
Eclipse-help-about eclipse -installation details,如果出现Mybatis的插件,证明安装成功

3.配置工具的参数信息
把这两个配置文件考到src目录下

4.工具生成文件的信息配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
<!-- 配置属性文件,这样有变更只需改配置文件 -->
<properties resource="generatorConfig.properties"/>
<!-- 制定mysql的驱动包的路径 千万别放中文路径下 -->
<classPathEntry location="C:\Users\msi\Desktop\mysql-connector-java-5.0.8.jar" />
<!-- 配置数据源和生成的代码所存放的位置 -->
<context id="tarena">
<!-- 是否生成注释 true不生成 false生成 -->
<commentGenerator>
<property name="suppressAllComments" value="${suppressAllComments}"/>
</commentGenerator>
<jdbcConnection driverClass="${driverClass}" connectionURL="${url}" userId="${username}" password="${password}" />
<!-- 所生成的实体类的位置默认资源包src -->
<javaModelGenerator targetPackage="${modeltargetPackage}" targetProject="${targetProject}" />
<!-- 所生成的sqlMap的影射文件的位置,默认资源包src -->
<sqlMapGenerator targetPackage="${sqltargetPackage}" targetProject="${targetProject}" />        
<javaClientGenerator targetPackage="${clienttargetPackage}" targetProject="${targetProject}" type="XMLMAPPER" /> 
 
<!-- 为哪些表生成代码 tableName:表名 schema:不用填写 -->
<table schema="" tableName="user_c" />
</context>
</generatorConfiguration>

5.属性配置文件的信息

suppressAllComments=false  指定不要生成过多的注释 
driverClass=com.mysql.jdbc.Driver  指定数据库驱动
url=jdbc\:mysql\://localhost\:3306/mybatis?characterEncoding\=utf-8  连接数据库 注意:写自己的路径
username=root   登录账户
password=admin  密码
modeltargetPackage=cn.tarena.mybatis.model  指定javabean生成的目录
targetProject=1507MybatisDay02  指定为哪个工程生成,本例中是1507MybatisDay02
sqltargetPackage=cn.tarena.mybatis.mapper  指定生成的映射文件在哪个目录下
clienttargetPackage=client  指定接口类生成的目录

接口方式


开发步骤:
1.创建一个业务接口,比如UserMapper,这个接口里专门定义和User相关的方法。
2.在service层里调用
持久层代码:

public void testInterfaceFindAll(){
SqlSession session=factory.openSession();
List<User> list=session.getMapper(UserMapper.class).findAll();
for(User u:list)System.out.println(u);
}

1.这个接口我放在了pojo包下,如果放在别的包下行不?
2.这个接口的名字叫UserMapper,换一个行不行?
3.接口里的方法 findAll,这个方法恰巧在xml文件里也有,如果我换个方法名行不行?
思考:这个接口是怎么生效的?
接口方式的工作原理:
1.在映射文件里,我们定义了一个namespace,命名空间:pojo.UserMapper,实际上,这个名字就是接口类的路径名,所以我们在创建接口类:UserMapper.class时,要建在pojo包下。
2.在接口里创建了findAll()方法,实际上调用的是映射文件里的id=findAll()方法,所以,这个方法名要保持一致。

注册mapper类型


我们知道每个mapper配置文件的namespace属性对应于某个接口,应用程序通过接口访问mybatis时,mybatis会为这个接口生成一个代理对象,这个对象就叫mapper对象,在生成代理对象前mybatis会校验接口是否已注册,未注册的接口会产生一个异常。为了避免这种异常,就需要注册mapper类型。这个步骤是在XMLMapperBuilder的bindMapperForNamespace方法中完成的。它通过调用Configuration对象的addMapper方法完成,而Configuration对象的addMapper方法是通过MapperRegistry的addMapper方法完成的,它只是简单的将namespace属性对应的接口类型存入本地缓存中。
Configuration对象提供了一个重载的addMappers(StringpackageName)方法,该方法以包路径名为参数,它的功能是自动扫描包路径下的接口并注册到MapperRegistry的缓存中,同时扫描包路径下的mapper配置文件并解析之。解析配置文件是在MapperAnnotationBuilder类的parse方法里完成的,该方法先解析配置文件,然后再解析接口里的注解配置,且注解里的配置会覆盖配置文件里的配置,也就是说注解的优先级高于配置文件,这点需要注意。采用自动扫描会大大简化配置,只不过需要应用程序自己调用,mybatis默认是不会调用这个方法的(后续将会讲解的spring集成mybatis就用到了自动扫描,敬请期待)。

Spring+SpringMVC+Mybatis整合


整合步骤:
1.创建一个web工程
2.引入整合所需要的jar包
3.引入Mybatis的核心配置文件
4.引入Mybtais的映射文件
5.引入Spring的配置文件
6.引入SPringMVC的配置文件
7.修改web.xml 配置Spring的容器加载的listener +SpringMVC的DispatcherServelt+中文乱码解决器
8.项目部署和测试

Mybatis核心配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
 
</configuration>

知识点:
这个配置文件虽然什么都没写,但是还是需要保留。后期会配置别名、驼峰映射规则、分页插件等,需要在这里配置

Spring核心配置文件:

<context:component-scan base-package="service"></context:component-scan>
 
<!-- 配置Mysql的数据源 -->
<bean id="dataSourceMysql" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost/mybatis?characterEncoding=utf-8"></property>
<property name="username" value="root"></property>
<property name="password" value="admin"></property>
</bean>
<!-- 配置Oracle的数据源 -->        
<bean id="dataSourceOracle" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:XE"></property>
<property name="username" value="1507htdb"></property>
<property name="password" value="htdb"></property>
</bean>
         
<!-- 配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSourceOracle"/>
<!-- 整合mybatis,加载核心配置文件sqlMapConfig.xml和所有的mapper文件 -->
<property name="configLocation" value="classpath:sqlMapConfig.xml"/>
<property name="mapperLocations" value="classpath:pojo/*.xml"/>
</bean>
 
<!-- 定义Mapper接口扫描器 ,将Mapper接口生成代理注入到spring-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描mapper包 -->
<property name="basePackage" value="mapper"/>
</bean>
         
<!-- 事务管理 -->        
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSourceOracle"/>
</bean>
 
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="view*" read-only="true"/>
 
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
 
<aop:config>
<aop:pointcut id="pc" expression="execution(* service.*.*(..))" />
<!--把事务控制在Service层-->
<aop:advisor pointcut-ref="pc" advice-ref="txAdvice" />
</aop:config>
</beans>

SpringMVC的配置文件:

  <!-- 配置HandlerMapping,Controller -->
      <mvc:annotation-driven/>
      <context:component-scan base-package="/controller"></context:component-scan>
    
      
      <!-- 内部资源视图解析器 规则:WEB/INF/pages/index.jsp   前缀+逻辑名+后缀 -->
      <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
              <property name="prefix" value="/WEB-INF/"/>
              <property name="suffix" value=".jsp"/>
      </bean>                
                                          
   
     <!-- 处理静态资源文件被 / 拦截的问题 -->             
    <mvc:default-servlet-handler/>

Web.xml代码:

<listener>
          <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
  <!-- 指定加载Spring的核心配置文件 -->
 
  <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:applicationContext.xml</param-value>
  </context-param>
  
  <!-- 配置SpringMVC核心入口类 -->
<servlet>
<servlet-name>smvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 改变核心配置文件的存储位置和命名-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-config.xml</param-value>
</init-param>
</servlet>
 
<servlet-mapping>
<servlet-name>smvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

框架分工


1.要明确每个框架的职责

as 解决同名字段


方式一:

select user_c.id,user_c.name,user_c.age,user_c.address,user_info.id as userinfoid,
user_info.name as userinfoname,user_info.job,user_info.hobbit from user_c left join
user_info on user_c.id=user_info.id

方式二:

select * from user_c left JOIN
(select id as userinfoid,name as userinfoname,job,hobbit from user_info)ui on user_c.id=ui.userinfoid

上一篇 55.java基础——零基础入门之Mybatis

猜你喜欢

转载自blog.csdn.net/qq_39188039/article/details/86620491