1 程序使用jdbc直接连接数据库问题总结
1、数据库连接频繁的创建和关闭,缺点浪费数据库的资源,影响操作效率
设想:使用数据库连接池
2、sql语句是硬编码,如果需求变更需要修改sql,就需要修改java代码,需要重新编译,系统不易维护。
设想:将sql语句统一配置在文件中,修改sql不需要修改java代码。
3、通过preparedStatement向占位符设置参数,存在硬编码( 参数位置,参数)问题。系统不易维护。
设想:将sql中的占位符及对应的参数类型配置在配置文件中,能够自动输入映射。
4、遍历查询结果集存在硬编码(列名)。
设想:自动进行sql查询结果向java对象的映射(输出映射)。
2 mybatis介绍
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,实质上Mybatis对ibatis进行一些改进。 目前mybatis在github上托管。
MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatemnt、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
2.1 mybatis架构
3 mybatis入门程序
3.1 开发环境
jdk1.6.0_45
myeclips10.0
mysql:mysql5.1
3.1.1 创建新的工程整个工程的整体目录如下:
3.2 导入jar包
从mybatis官网下载(地址:https://github.com/mybatis/mybatis-3/releases)
mybatis-3.2.7.pdf---操作手册
mybatis-3.2.7.jar--核心 jar包
依赖的jar包
需要数据库的驱动包:
Mysql-connector-java-5.1.7-bin
3.2.1 数据模型
数据库中有已经导入的四个表:items:(商品信息表);orderdetail:(订单明细表);orders:(订单表);user:(用户表)
1 CREATE TABLE items (
2 id INT NOT NULL AUTO_INCREMENT,
3 itemsname VARCHAR(32) NOT NULL COMMENT '商品名称',
4 price FLOAT(10,1) NOT NULL COMMENT '商品定价',
5 detail TEXT COMMENT '商品描述',
6 pic VARCHAR(64) DEFAULT NULL COMMENT '商品图片',
7 createtime DATETIME NOT NULL COMMENT '生产日期',
8 PRIMARY KEY (id)
9 ) DEFAULT CHARSET=utf8;
10
11 /*Table structure for table `orderdetail` */
12
13 CREATE TABLE orderdetail (
14 id INT NOT NULL AUTO_INCREMENT,
15 orders_id INT NOT NULL COMMENT '订单id',
16 items_id INT NOT NULL COMMENT '商品id',
17 items_num INT DEFAULT NULL COMMENT '商品购买数量',
18 PRIMARY KEY (id),
19 KEY `FK_orderdetail_1` (`orders_id`),
20 KEY `FK_orderdetail_2` (`items_id`),
21 CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
22 CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
23 ) DEFAULT CHARSET=utf8;
24
25 /*Table structure for table `orders` */
26
27 CREATE TABLE orders (
28 id INT NOT NULL AUTO_INCREMENT,
29 user_id INT NOT NULL COMMENT '下单用户id',
30 number VARCHAR(30) NOT NULL COMMENT '订单号',
31 createtime DATETIME NOT NULL COMMENT '创建订单时间',
32 note VARCHAR(100) DEFAULT NULL COMMENT '备注',
33 PRIMARY KEY (`id`),
34 KEY `FK_orders_1` (`user_id`),
35 CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
36 ) DEFAULT CHARSET=utf8;
37
38 /*Table structure for table `t_user` */
39
40 CREATE TABLE user (
41 id INT NOT NULL AUTO_INCREMENT,
42 username VARCHAR(32) NOT NULL COMMENT '用户名称',
43 birthday DATE DEFAULT NULL COMMENT '生日',
44 sex CHAR(1) DEFAULT NULL COMMENT '性别',
45 address VARCHAR(256) DEFAULT NULL COMMENT '地址',
46 PRIMARY KEY (`id`)
47 ) DEFAULT CHARSET=utf8;
测试数据代码:
1 /*Data for the table `items` */
2
3 INSERT INTO items(itemsname,price,detail,pic,createtime) VALUES
4 ('台式机',3000.0,'该电脑质量非常好!',NULL,'2015-07-07 13:28:53'),
5 ('笔记本',6000.0,'笔记本性能好,质量好!',NULL,'2015-07-08 13:22:57'),
6 ('背包',200.0,'名牌背包,容量大质量好!',NULL,'2015-07-010 13:25:02');
7
8 /*Data for the table `orderdetail` */
9
10 INSERT INTO `orderdetail`(`orders_id`,`items_id`,`items_num`) VALUES
11 (1,1,1),
12 (1,2,3),
13 (2,3,4),
14 (3,2,3);
15
16 /*Data for the table `orders` */
17
18 INSERT INTO `orders`(`user_id`,`number`,`createtime`,`note`) VALUES
19 (1,'1000010','2015-06-04 13:22:35',NULL),
20 (1,'1000011','2015-07-08 13:22:41',NULL),
21 (2,'1000012','2015-07-17 14:13:23',NULL),
22 (3,'1000012','2015-07-16 18:13:23',NULL),
23 (4,'1000012','2015-07-15 19:13:23',NULL),
24 (5,'1000012','2015-07-14 17:13:23',NULL),
25 (6,'1000012','2015-07-13 16:13:23',NULL);
26
27 /*Data for the table `user` */
28
29 INSERT INTO `user`(`username`,`birthday`,`sex`,`address`) VALUES
30 ('王五',NULL,'2',NULL),
31 ('张三','2014-07-10','1','北京市'),
32 ('张小明',NULL,'1','河南郑州'),
33 ('陈小明',NULL,'1','河南郑州'),
34 ('张三丰',NULL,'1','河南郑州'),
35 ('陈小明',NULL,'1','河南郑州'),
36 ('王五',NULL,NULL,NULL),
37 ('小A','2015-06-27','2','北京'),
38 ('小B','2015-06-27','2','北京'),
39 ('小C','2015-06-27','1','北京'),
40 ('小D','2015-06-27','2','北京');
3.3 需求
实现用户查询:
根据用户id(主键)查询用户信息(单条记录)
3.4 log4j.properties(公用文件)
#Global logging configuration,建议开发环境中要用debug
log4j.rootLogger=DEBUG, stdout
#Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
3.5 db.properties(公用文件)
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
3.6 SqlMapConfig.xml(公用文件)
通过SqlMapConfig.xml加载mybatis运行环境。
<!DOCTYPEconfiguration
PUBLIC"-//mybatis.org//DTDConfig 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 属性定义
加载一个properties文件db.properties是和数据库连接的一些信息
在 properties标签中配置属性值
-->
<propertiesresource="db.properties">
</properties>
<!-- 和spring整合后 environments配置将废除-->
<environmentsdefault="development">
<environmentid="development">
<!--使用jdbc事务管理-->
<transactionManagertype="JDBC"/>
<!--数据库连接池-->
<dataSourcetype="POOLED">
<propertyname="driver"value="${jdbc.driver}"/>
<propertyname="url"value="${jdbc.url}"/>
<propertyname="username"value="${jdbc.username}"/>
<propertyname="password"value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!--通过resource引用mapper的映射文件 -->
<mapperresource="sqlmap/User.xml"/>
</mappers>
</configuration>
3.7 根据id查询用户
3.7.1 pojo(User.java)然后加上get()和set()方法
3.7.2 User.xml(重点)
建议命名规则:表名+mapper.xml
早期ibatis命名规则:表名.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEmapper
PUBLIC"-//mybatis.org//DTDMapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace命名空间,为了对sql语句进行隔离,方便管理,mapper开发dao方式,使用namespace有特殊作用
mapper代理开发时将namespace指定为mapper接口的全限定名
-->
<mappernamespace="firstDemo">
<!--在mapper.xml文件中配置很多的sql语句,执行每个sql语句时,封装为MappedStatement对象
mapper.xml以statement为单位管理sql语句
-->
<!-- 根据id查询用户信息 -->
<!--
id:唯一标识一个statement
#{}:表示一个占位符,如果#{}中传入简单类型的参数,#{}中的名称随意
parameterType:输入参数的类型,通过#{}接收parameterType输入的参数
resultType:输出结果类型,不管返回是多条还是单条,指定单条记录映射的pojo类型
-->
<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">
SELECT * FROM USER WHERE id= #{id}
</select>
</mapper>
3.7.3 编码并写测试程序FirstTest.java
package com.itcast.test;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
importorg.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
importorg.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import cn.itcast.mybatis.po.User;
public class FirstTest {
//定义一个会话工厂
private SqlSessionFactory sqlSessionFactory;
@Before
publicvoid init() throws IOException {
//加载配置文件
String resource = "sqlMapConfig.xml";
//加载文件到输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
}
/*
* 测试根据Id查询用户获取单条记录
*/
@Test
publicvoid testFindUserById(){
//通过sqlSessionFactory创建sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//通过sqlSession操作数据库
//第一个参数:statment的位置,等于namespace+statment的id
//第二个参数:传入的参数
User user = null;
try{
user= sqlSession.selectOne("firstDemo.findUserById", 26);
}catch (Exception e) {
e.printStackTrace();
}finally{
//关闭sqlSession
//这里放在try/catch语句的finally确保查询之后能关闭sqlSession
sqlSession.close();
}
System.out.println(user);
}
}
4 Mybatis解决了jdbc编程的哪些问题
1、 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:在SqlMapConfig.xml中配置数据链接池,使用连接池管理数据库链接。
2、 Sql语句写在代码中造成代码不易维护,实际应用sql变化的可能较大,sql变动需要改变java代码。
解决:将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
3、 向sql语句传参数麻烦,因为sql语句的where条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决:Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
4、 对结果集解析麻烦,sql变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo对象解析比较方便。
解决:Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。