一个基本配置文件
Configuration.xml 主要是用来配置mybatis的行为以及数据库的连接信息
Mappers是映射器,基本上是写一个实体类就有一个相应的sql操作xml文档,所以也就是多个映射器。
Environment是环境id,默认的环境和环境 ID 是一目了然的。随你怎么命名,只要保证默认环境要匹配其中一个环境ID。
映射的sql文档
ParameterType可以省略
#{id} 当id的值被传入这个sql语句时把id当成一个?号,#把id的值自动加上双引号,并进行预编译相当于执行prepareStatement()语句,#{} 的参数替换是发生在 DBMS 中,而 ${} 则发生在动态解析过程中。
使用
Mybatis返回一个list记录所有结果
xml映射
<mappernamespace="com.yihaomen.mybatis.models.UserMapper">
<resultMap type="User"id="UserList">
<resultproperty="id" column="id" />
<resultproperty="userName" column="userName"/>
<resultproperty="userAge" column="userAge" />
<resultproperty="userAddress" column="userAddress"/>
</resultMap>
<selectid="selectUserByID" resultMap="UserList">
select * from `user`
</select>
</mapper>
首先说一下sqlSession.selectOne()函数,它只能查询一条数据,如果表中的记录多于一条就会报错,空数据不会报错,也就是说当表中有一条或者没有数据时都会正常执行。
但如果想查询多条结果呢,就需要指定resultMap了,不仅要添加resultMap,还要在下面的sql具体语句中将resultType给改为resultMap
使用;
java.util.List<User>L = session.selectList("com.yihaomen.mybatis.models.UserMapper.selectUserByID");
for (User u : L) {
System.out.println(u.getId()+u.getUserName()+u.getUserAge()+u.getUserAddress());}
mybatis使用接口编程
1. 通过在接口中添加注解的方式
package com.yihaomen.mybatis.inter;
importorg.apache.ibatis.annotations.Select;
import com.yihaomen.mybatis.model.User;;
public interface IUserOperation {
@Select("select* from User where id=#{id}")
public UserselectUserByID(int id);
}
*一个xml映射似乎只能放一个映射器mapper,mappers只能在mybatis的基本配置Configuration中出现,不能在xml映射中出现。
添加完成注解后,
</mapper>
<mappernamespace="com.yihaomen.mybatis.inter.IUserOperation"></mapper>
</mappers>
Xml映射如上,就没有了sql语句,调用时正常调用就行
IUserOperation iUserOperation = session.getMapper(IUserOperation.class);
User u =iUserOperation.selectUserByID(1);
System.out.println(u.getUserName()+u.getUserAddress());
2. 通过xml+dao的方式
Dao层代码:只实现了方法名不需要方法体
package com.yihaomen.mybatis.inter;
import org.apache.ibatis.annotations.Select;
import com.yihaomen.mybatis.model.User;;
public interface IUserOperation {
public UserselectUserByID(int id);
}
Xml:select id需要与接口里的方法一致
<mappernamespace="com.yihaomen.mybatis.inter.IUserOperation" >
<selectid="selectUserByID" resultType="User">
select *from `user` where id = #{id}
</select>
</mapper>
调用无变化
增删改
Insert:
Xml映射文档insert和update中有useGeneratedKeys、keyProperty、keyColumn,如果表中的有数据是自增的,使用useGeneratedKeys来设定为true,keyProperty是指定自增的列名,keyColumn是当第一个字段不是自增是使用。
Xml映射文档:
<mapper namespace="com.yihaomen.mybatis.inter.IUserOperation">
<select id="selectUserByID" resultType="User">
select * from `user` where id = #{id}
</select>
<insert id="insertUser" parameterType="User" >
insertinto user (id,userName,userAge,userAddress) values(#{id},#{userName},#{userAge},#{userAddress})
</insert>
</mapper>
Dao层:
import com.yihaomen.mybatis.model.User;;
public interface IUserOperation {
public User selectUserByID(intid);
public void insertUser(User u);
}
调用时需要注意,sqlsession有一个commit()函数,需要提交一下:,增加后,必须提交事务,否则不会写入到数据库.
public static void main(String[] args) {
SqlSession session = sqlSessionFactory.openSession();
try{
IUserOperation iUserOperation =session.getMapper(IUserOperation.class);
User u =iUserOperation.selectUserByID(1);
System.out.println(u.getUserName()+u.getUserAddress());
User u1 = newUser();
u1.setId(14);
u1.setUserAddress("aaa");
u1.setUserAge("42");
u1.setUserName("12wq");
iUserOperation.insertUser(u1);
session.commit();
} finally{
session.close();
}
}
Update:也需要commit()
Xml配置文件:
<update id="updateUser" parameterType="User">
updateUser set UserName = #{userName} where id=#{id}
</update>
Dao层:
public void updateUser(User u);
调用:
User u2 = newUser();
u2.setId(14);
u2.setUserName("qqqq");
iUserOperation.updateUser(u2);
session.commit();
delete:与上面类似
多表查询:多对一,例如有用户表和文章表,一个用户可以发表多个文章。
这个时候就需要resultMap和association来结合使用了。文章表中有用户的id,这个时候虽然文章表中只有用户的属性,在建立实体类封装时依然要给文章这个类存入User,而不是User的id
多表查询xml映射有两种配置方法:
(1)将一的result写入association中,把association放入多的resultMap中
这里存在一个问题,如果数据库中的文章表的字段和用户的字段一样的(如上面的id),mybatis就只能查出第一条数据,怎么解决呢?在xml的映射中resultMap里把column设置成别名,在下面的select的sql的语句里相应部分也给设成别名。如下面的xml映射就将article的id设置了别名(另:property应该是数据库或者实体类中的字段名,column可以修改应该是mybatis映射的字段名):
<mapper namespace="com.yihaomen.mybatis.inter.IUserOperation">
<resultMap type="Article"id="resultMapList">
<id property="id"column="aid"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
<association property="user" javaType="User">
<id property="id" column="id"/>
<result property="userName" column="userName"/>
<result property="userAge" column="userAge"/>
<result property="userAddress" column="userAddress"/>
</association>
</resultMap>
<select id="selectArticleUser" resultMap="resultMapList">
select user.userName,user.userAddress,article.id aid fromuser,article
where user.id=article.userid ;
</select>
</mapper>
(2)xml映射的第二种写法:
将一的内容写入resultMap中,放在多的内容外,多的内容除了写多的内容,只加入association,而association中不用再加入内容,但是需要在association中多设置一个resultmap指向刚设置好的一的resultmap的id
<resultMap id="usermap" type="User">
<result property="id" column="id"/>
<result property="userName" column="userName"/>
<result property="userAge" column="userAge"/>
<result property="userAddress" column="userAddress"/>
</resultMap>
<resultMap type="Article" id="articleMap">
<result property="id" column="aid"/>
<result property="title" column="title"/>
<result property="content" column="content"/>
<association property="user" javaType="User"resultMap="usermap" />
</resultMap>
<select id="selectArticleUser" resultMap="articleMap">
select user.userName,user.userAddress,article.id aid fromuser,article
where user.id=article.userid ;
</select>
两种映射的比较,第二种方法相当于把association里面的内容给抽取出来了,这样别的resultMap也可以使用
Dao层:publicList<Article> selectArticleUser();
调用:
List<Article> articles =iUserOperation.selectArticleUser();
for(Articlearticle:articles){
System.out.println(
"名字:"+article.getUser().getUserName()+""+"地址:"+article.getUser().getUserAddress()
+"文章内容:"+article.getContent()+articles.size());
}
另:需要注意一点,如果调用时打印出在xml映射的select中sql中没有查的字段会打印出null,如上面article的content就是null
Mybatis 与 Spring的集合
在配置Spring的配置文件时遇到一个很恶心的事情,因为xml中的priperty配置时少些了一个斜杠,老是报
Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 18 in XML document from class path resource[config/applicationContext.xml] is invalid; nested exception isorg.xml.sax.SAXParseException; lineNumber: 18; columnNumber: 45;cvc-complex-type.2.4.a: 发现了以元素 'property' 开头的无效内容。应以 '{"http://www.springframework.org/schema/beans":description,"http://www.springframework.org/schema/beans":meta,"http://www.springframework.org/schema/beans":bean,"http://www.springframework.org/schema/beans":ref,"http://www.springframework.org/schema/beans":idref,"http://www.springframework.org/schema/beans":value,"http://www.springframework.org/schema/beans":null,"http://www.springframework.org/schema/beans":array,"http://www.springframework.org/schema/beans":list,"http://www.springframework.org/schema/beans":set,"http://www.springframework.org/schema/beans":map,"http://www.springframework.org/schema/beans":props, WC[##other:"http://www.springframework.org/schema/beans"]}'之一开头。
at
这样的错误,一直以为是xml的头文件的引用错误,找了半天,最后终于发现了是少了一个斜杠引起的。
首先需要一个spring配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jeehttp://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-3.0.xsd"
default-autowire="byName"default-lazy-init="false">
<bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">
<!--dataSource属性指定要用到的连接池-->
<property name="dataSource" ref="dataSource"/>
<!--configLocation属性指定mybatis的核心配置文件-->
<property name="configLocation" value="config/Configuration.xml"/>
</bean>
<bean id="userMapper"class="org.mybatis.spring.mapper.MapperFactoryBean">
<!--sqlSessionFactory属性指定要用到的SqlSessionFactory实例-->
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<!--mapperInterface属性指定映射器接口,用于实现此接口并生成映射器对象-->
<property name="mapperInterface" value="com.yihaomen.mybatis.inter.IUserOperation"/>
</bean> </beans>
这里以applicationContext-mybatis.xml来体现,配置了如下信息:
注册数据源,常见的有JDBC或JNDI,根据具体情况择一。
注册sqlSessionFactory
sqlSessionFactory是用来生产sqlSession以操作数据库的,所以,需指定sqlSessionFactory所引用的数据源
指定相应的SQL Mapper文件在哪里。我们自命名“_mapper后缀的xml文件”,主要用来定义SQL;“_resultmap后缀的xml文件”,则主要用来定义DB字段与应用程序实体属性的映射。
指定相应的应用程序实体在哪里,并自动注册不包含package名的别名
在哪些package下扫描Mapper接口,即DAO接口
调用:
private static ApplicationContext ctx;
static{
ctx = new ClassPathXmlApplicationContext("config/applicationContext.xml");
//在mybatis里这一步是加载configuration.xml,而在这里这一步变成了加载Spring的配置文件
}
public static void main(String []args){
IUserOperation mapperIUserOperation = (IUserOperation) ctx.getBean("userMapper");
//在mybatis里这一步是使用sqlsession的getMapper来加载接口的class文件,而在这却是使用Spring的xml配置的bean来找到那个接口
System.out.print("--------------\n");
List<Article> arList =mapperIUserOperation.selectArticleUser();
for (Article article : arList){
System.out.println("--"+article.getContent()+"--"+article.getTitle()+"--"+article.getId()+"--"+article.getUser().getUserName());
}
}
Mybatis与Spring与Springmvc的集合
Web.xml的配置信息
包含Spring的基本配置文档
包含Springmvc的分发器的基本文档
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:config/applicationContext.xml
</param-value>
</context-param>
<!-- 配置Spring上下文监听器,它的作用就是在启动WEB容器时,就会自动装在我们applicationContext.xml配置-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:config/springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Spring的Applicationcontext.xml文档
包含数据库的配置
包含一些service层的注册bean
包含sqlsession工厂的配置
包含与Spring集合的mybatis的基本文档信息
包含接口的注册bean
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8"
p:username="root" p:password="root"
>
</bean>
<context:component-scan base-package="com.test.service"/>
<bean id="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">
<!--dataSource属性指定要用到的连接池-->
<property name="dataSource" ref="dataSource"/>
<!--configLocation属性指定mybatis的核心配置文件-->
<property name="configLocation" value="classpath:config/Configuration.xml"/>
<!-- 所有配置的mapper文件 通过ClassPathXmlApplicationContext。getbean()时传入小写的接口名 -->
<property name="mapperLocations" value="classpath*:com/test/mapper/*.xml" />
</bean>
Mybatis的配置信息
包含实体类的别名配置
<configuration>
<typeAliases>
<typeAlias alias="User" type="com.test.model.User"/>
<typeAlias alias="Article" type="com.test.model.Article"/>
</typeAliases>
</configuration>
映射Xml
调用:
@Controller
@RequestMapping("/mvc")
public class UserController {
@Autowired
ArticleInter art;
@RequestMapping("/list")
@ResponseBody
public void show (HttpServletRequest request,HttpServletResponse response) throwsIOException{
PrintWriter pw = response.getWriter();
List<Article>list = art.getListArticle();
for(Article article : list) {
System.out.println(article.getId()+"--"+article.getTitle()+article.getContent()+"--"+article.getUser().getUserAddress());
pw.write(article.getId()+"--"+article.getTitle()+article.getContent()+"--"+article.getUser().getUserAddress());
pw.write("123");
}
}
}
遇到一个问题,在运行时一直报接口的方法的空指针的错误,调试之后发现接口的值为空,
十一月 16, 2017 1:23:44 下午 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet [mvc-dispatcher] in context with path [/TheNewTest] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at com.test.controller.UserController.show(UserController.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:100)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:604)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:565)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:799)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1457)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
后来发现是少了@Autowired,它的作用是对于bean当中引用的其他bean不需要我们自己去配置它该使用哪个类,Spring 的自动装配可以帮助我们完成这些工作。