day20191010ClassNotes
笔记:
1.DAO模式组成部分:
程序 ----> 数据库
实体类 数据库中的表
工具类:公共的数据库连接、关闭、公共的增删改、查询
接口 : 程序提倡的是面向接口编程,从而降低程序的耦合性
实现类 : 通过不同的需求实现不同的接口
2.传统的Web应用组成分层( MVC 模式)
M : 模型 【 持久化对象(实体类) + DAO(数据访问层) + Service(业务访问层) 】
V : 视图 【客户端显示的页面(html,jsp,asp,php...)】
C : 控制层 【Servlet,前后台数据交互中转站】
3.使用JDBC操作数据库
执行过程: Java程序和数据库之间的数据交互。
数据库中的数据一一读取到程序(内存)中
数据库方向: 数据库数据 ---> 库 ---> 表 ----> 数据类型 字段列
程序方向: 程序 ----> 实体类-----> 数据类型 属性
4.DAO的设计模式
实体类
5.使用JDBC操作数据库步骤
5.1.加载驱动jar包
5.2.写BaseUtils工具类
5.3.实体类(遵循数据的一张表对应一个实体类)
5.4.接口(CRUD:增删改查__查:根据条件查询)
5.5.实现类
5.6.测试类
6.单例模式
概念:
一> 单例本身有且只有一个实例对象
二> 单例类必须自己创建唯一的实例对象
三> 单例类需要给其他实例对象提供调用该单例类的实例对象方法
单例主要解决的问题: 频繁的创建与消耗实例对象,节省内存资源消耗。
单例模式有哪些?
懒汉式:
优点 :等实例对象需要使用时再判断当前实例对象是否为空,不为空则返回,为空,则创建,节省内存资源;
缺点: 多线程使用场景下,不安全
饿汉式
优点 : 线程安全
缺点: 不管当前实例对象是否使用使用,加载时即创建实例,浪费内存资源
7.常见异常信息:
1).You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'u.username = '??·?'AND u.password = '123'' at line 1:
sql语句错误
2).java.sql.SQLException: Parameter index out of range (2 > number of parameters, which is 1).
找到了1个问号,却插入了2个值,导致参数越界
3).java.sql.SQLException: No value specified for parameter 2
缺少传递的占位符参数
8.进销存需求:
1 )用户登录
2 )退出登录 (JavaWeb的jsp数据交互)
3 )销售
4 )对销售记录进行分页查询并根据销售日期排序(降序)
5 )根据商品名称查询该商品的库存数量
eclipse创建java project文件
sale.sql文件
##用户表
CREATE TABLE `test`.`users`(
`id` INT(10) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` VARCHAR(20) NOT NULL COMMENT '用户名',
`password` VARCHAR(20) NOT NULL COMMENT '密码',
`realnam` VARCHAR(20) NOT NULL COMMENT '真实姓名',
PRIMARY KEY (`id`)
); ##商品表
CREATE TABLE `test`.`product`(
`id` INT(10) NOT NULL AUTO_INCREMENT COMMENT '商品 id',
`productname` VARCHAR(30) NOT NULL COMMENT '商品名称',
`quantity` INT(10) NOT NULL COMMENT '库存量',
PRIMARY KEY (`id`)
); ##销售记录表 从表
CREATE TABLE `test`.`sale`(
`id` INT(10) NOT NULL AUTO_INCREMENT COMMENT '记录 id',
`price` DOUBLE(11,2) NOT NULL COMMENT '销售单价',
`quantity` INT(10) NOT NULL COMMENT '数量',
`totalprice` DOUBLE(10,2) NOT NULL COMMENT '总价',
`saledate` DATE NOT NULL COMMENT '销售日期',
`userid` INT(10) NOT NULL COMMENT '销售员 id,对应 users 表的主键',
`productid` INT(10) NOT NULL COMMENT '商品 id,对应 product 表的主键',
PRIMARY KEY (`id`),
CONSTRAINT `fk_uid` FOREIGN KEY (`userid`) REFERENCES `test`.`users`(`id`),
CONSTRAINT `fk_pid` FOREIGN KEY (`productid`) REFERENCES `test`.`product`(`id`)
); ##添加测试数据 ,先加主表再加从表
INSERT INTO users(username,PASSWORD,realnam) VALUES('小飞','','刁志飞') ;
INSERT INTO users(username,PASSWORD,realnam) VALUES('小刘','','刘鑫') ;
INSERT INTO users(username,PASSWORD,realnam) VALUES('大刘','','刘正') ; INSERT INTO product(productname,quantity) VALUES('可口可乐',200) ;
INSERT INTO product(productname,quantity) VALUES('冰红茶',500) ;
INSERT INTO product(productname,quantity) VALUES('咖啡',10000) ; INSERT INTO sale(price,quantity,totalprice,saledate,userid,productid) VALUES(2,50,100,NOW(),1,1) ;
INSERT INTO sale(price,quantity,totalprice,saledate,userid,productid) VALUES(5,50,250,NOW(),2,2) ;
INSERT INTO sale(price,quantity,totalprice,saledate,userid,productid) VALUES(2,50,100,NOW(),3,1) ;
INSERT INTO sale(price,quantity,totalprice,saledate,userid,productid) VALUES(10,50,500,NOW(),3,3) ;
INSERT INTO sale(price,quantity,totalprice,saledate,userid,productid) VALUES(3,50,150,NOW(),2,1) ;
INSERT INTO sale(price,quantity,totalprice,saledate,userid,productid) VALUES(6,50,300,NOW(),3,2) ; ## 三表连接查询
SELECT s.id,price,s.quantity,totalprice,saledate,userid,productid,u.`realnam`,p.`productname` FROM sale s
LEFT JOIN users u ON u.`id` = s.`userid`
LEFT JOIN product p ON p.`id` = s.`productid` ORDER BY s.`saledate` DESC
sale.sql
utils包中放入BaseUtils.java文件夹中
文件夹(写BaseUtils工具类):
package com.kgc.kh76.utils; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; public class BaseUtils {
// 定义连接数据库信息
protected static final String DRIVER = "com.mysql.jdbc.Driver";
protected static final String URL = "jdbc:mysql://127.0.0.1/test";
protected static final String USER = "root";
protected static final String PASSWORD = "ok"; // 定义数据库连接对象、预编译sql语句传输通道、rs结果集
protected Connection conn = null;
protected PreparedStatement pstmt = null;
protected ResultSet rs = null; // 加载驱动
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} // 创建数据库连接对象
public Connection getConn() {
try {
return DriverManager.getConnection(URL, USER, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
} // 关闭所有数据库连接对象
public void closeAll() {
try {
if (rs != null) {
rs.close();
}
if (pstmt != null) {
pstmt.close();
}
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* 公共的查询方法
*
* @param sql 传输的sql语句
* @param params 预编译占位符参数
* @return 查询的rs结果集
*/
public ResultSet executeQuery(String sql, Object... params) {
// 连接数据库
conn = getConn();
try {
// 创建数据库传输通道
pstmt = conn.prepareStatement(sql);
// 循环遍历占位符参数
for (int i = 0; i < params.length; i++) {
// 设置占位符参数
pstmt.setObject(i + 1, params[i]);
}
// 触发执行查询sql语句
rs = pstmt.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
} /**
* 公共的增删改操作
* @param sql 传输的sql语句
* @param params 预编译占位符参数
* @return 执行增删改操作受影响的行数
*/
public int executeUpdate(String sql, Object... params) {
// 连接数据库
conn = getConn();
// 执行增删改操作受影响的行数
int result = 0;
try {
// 创建数据库传输通道
pstmt = conn.prepareStatement(sql);
// 循环遍历占位符参数
for (int i = 0; i < params.length; i++) {
// 设置占位符参数
pstmt.setObject(i + 1, params[i]);
}
// 触发执行增删改sql语句
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 调用关闭所有数据库连接对象
closeAll();
}
return result;
}
}
BaseUtils.java
Entitiy实体类(遵循数据的一张表对应一个实体类) :
Product.java:
package com.kgc.kh76.entity; public class Product {
private int id; //INT(10) NOT NULL AUTO_INCREMENT COMMENT '商品 id',
private String productname; //VARCHAR(30) NOT NULL COMMENT '商品名称',
private int quantity; //INT(10) NOT NULL COMMENT '库存量',
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getProductname() {
return productname;
}
public void setProductname(String productname) {
this.productname = productname;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
} public Product() {
}
public Product(int id, String productname, int quantity) {
super();
this.id = id;
this.productname = productname;
this.quantity = quantity;
}
@Override
public String toString() {
return "Product [id=" + id + ", productname=" + productname + ", quantity=" + quantity + "]";
}
}
Product.java
Sale.java:
package com.kgc.kh76.entity; public class Sale {
private int id; // INT(10) NOT NULL AUTO_INCREMENT COMMENT '记录 id',
private double price; // DOUBLE(11,2) NOT NULL COMMENT '销售单价',
private int quantity; // INT(10) NOT NULL COMMENT '数量',
private double totalprice; // DOUBLE(10,2) NOT NULL COMMENT '总价',
private String saledate; // DATE NOT NULL COMMENT '销售日期', private Users user; // INT(10) NOT NULL COMMENT '销售员 id,对应 users 表的主键',
private Product product; // INT(10) NOT NULL COMMENT '商品 id,对应 product 表的主键',
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public double getTotalprice() {
return totalprice;
}
public void setTotalprice(double totalprice) {
this.totalprice = totalprice;
}
public String getSaledate() {
return saledate;
}
public void setSaledate(String saledate) {
this.saledate = saledate;
}
public Users getUser() {
return user;
}
public void setUser(Users user) {
this.user = user;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
} public Sale() {
}
public Sale(int id, double price, int quantity, double totalprice, String saledate, Users user, Product product) {
this.id = id;
this.price = price;
this.quantity = quantity;
this.totalprice = totalprice;
this.saledate = saledate;
this.user = user;
this.product = product;
}
@Override
public String toString() {
return "Sale [id=" + id + ", price=" + price + ", quantity=" + quantity + ", totalprice=" + totalprice
+ ", saledate=" + saledate + ", user=" + user + ", product=" + product + "]";
}
}
Sale.java
Users.java:
package com.kgc.kh76.entity; public class Users {
private int id; //INT(10) NOT NULL AUTO_INCREMENT COMMENT '用户id',
private String username; //VARCHAR(20) NOT NULL COMMENT '用户名',
private String password; //VARCHAR(20) NOT NULL COMMENT '密码',
private String realnam; //VARCHAR(20) NOT NULL COMMENT '真实姓名',
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRealnam() {
return realnam;
}
public void setRealnam(String realnam) {
this.realnam = realnam;
} public Users() {
}
public Users(int id, String username, String password, String realnam) {
this.id = id;
this.username = username;
this.password = password;
this.realnam = realnam;
}
@Override
public String toString() {
return "Users [id=" + id + ", username=" + username + ", password=" + password + ", realnam=" + realnam + "]";
}
}
Users.java
5.4.接口(CRUD:增删改查__查:根据条件查询)
dao文件夹接口
ProductDao.java
package com.kgc.kh76.dao; import com.kgc.kh76.entity.Product; public interface ProductDao {
// 对于商品表 减少库存
// 根据商品id更新商品库存的方法
int updateProductById(Product pro); //根据商品名称查询该商品的库存数量
int productQuantity(String proName);
}
ProductDao.java
SaleDao.java
package com.kgc.kh76.dao; import java.util.List; import com.kgc.kh76.entity.Sale; public interface SaleDao {
//添加销售记录表
// 基本信息 : 商品名称 单价 数量
int addSale(Sale sale); //查询所有销售记录
//对销售记录进行分页查询并根据销售日期排序(降序)
List<Sale> queryAllSales(); //根据销售记录ID修改销售记录信息
int updateSaleById(Sale sale);
}
SaleDao.java
UsersDao.java
package com.kgc.kh76.dao; import com.kgc.kh76.entity.Users; public interface UsersDao {
//根据用户名和密码查询方法
Users queryUserByUnameAndPwd(String uname,String pwd); //强调: 一般项目,删除是很少应用的
}
UsersDao.java
5.5.实现类dao包中的impl包
package com.kgc.kh76.dao.impl; import java.sql.SQLException; import com.kgc.kh76.dao.ProductDao;
import com.kgc.kh76.entity.Product;
import com.kgc.kh76.utils.BaseUtils; public class ProductDaoImpl extends BaseUtils implements ProductDao { @Override
public int updateProductById(Product pro) {
String sql = " UPDATE `product` SET `productname` = ?,`quantity` = ? WHERE id = ? ";
Object[] params = {pro.getProductname(),pro.getQuantity(),pro.getId()};
return super.executeUpdate(sql, params);
} @Override
public int productQuantity(String proName) {
String sql = "SELECT p.`quantity` FROM `product` p "
+ " WHERE p.`productname` = ? ";
rs = super.executeQuery(sql, new Object[] {proName});
//定义num数量
int num = 0;
try {
if(rs.next()) {
num = rs.getInt("p.quantity");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
super.closeAll();
}
return num;
} }
ProductDaoImpl.java
package com.kgc.kh76.dao.impl; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List; import com.kgc.kh76.dao.SaleDao;
import com.kgc.kh76.entity.Product;
import com.kgc.kh76.entity.Sale;
import com.kgc.kh76.entity.Users;
import com.kgc.kh76.utils.BaseUtils; public class SaleDaoImpl extends BaseUtils implements SaleDao { @Override
public int addSale(Sale s) {
String sql = "INSERT INTO sale(price,quantity,"
+ "totalprice,saledate,userid,productid) VALUES(?,?,?,NOW(),?,?) ";
int addRes = super.executeUpdate(sql, new Object[] {s.getPrice(),s.getQuantity(),s.getTotalprice(),
s.getUser().getId(),s.getProduct().getId()});
return addRes;
} @Override
public List<Sale> queryAllSales() {
//创建List<Sale>集合对象,用来存储数据库获取的rs结果集
List<Sale> sales = new ArrayList<Sale>();
//定义查询sql语句
StringBuffer sb = new StringBuffer();
sb.append(" SELECT s.id,price,s.quantity,totalprice,saledate,userid,productid,u.`realnam`,p.`productname` ");
sb.append(" FROM sale s ");
sb.append(" LEFT JOIN users u ON u.`id` = s.`userid` ");
sb.append(" LEFT JOIN product p ON p.`id` = s.`productid` ");
sb.append(" ORDER BY s.`saledate` DESC "); //调用公共查询的方法
super.rs = super.executeQuery(sb.toString());
try {
//循环遍历rs结果集
while(rs.next()) {
//创建Sale销售记录对象,将从数据循环遍历的数据赋值给实体类对象
Sale sale = new Sale(rs.getInt("s.id"),
rs.getDouble("price"),
rs.getInt("s.quantity"),
rs.getDouble("totalprice"),
rs.getString("saledate"),
new Users(rs.getInt("userid"), null, null, rs.getString("u.realnam")),
new Product(rs.getInt("productid"), rs.getString("p.productname"), 0));
sales.add(sale);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
super.closeAll();
}
return sales;
} @Override
public int updateSaleById(Sale s) {
String sql = " UPDATE sale s SET s.`price` = ? ,s.`quantity` = ?,"
+ " s.`totalprice` = ? ,s.`saledate` = ? , " +
" s.`userid` = ? ,s.`productid` = ? WHERE s.`id` = ? ";
return super.executeUpdate(sql, new Object[] {s.getPrice(),s.getQuantity(),s.getTotalprice(),
s.getSaledate(),s.getUser().getId(),
s.getProduct().getId(),s.getId()});
} }
SaleDaoImpl.java
package com.kgc.kh76.dao.impl; import java.sql.SQLException; import com.kgc.kh76.dao.UsersDao;
import com.kgc.kh76.entity.Users;
import com.kgc.kh76.utils.BaseUtils; public class UsersDaoImpl extends BaseUtils implements UsersDao { @Override
public Users queryUserByUnameAndPwd(String uname, String pwd) {
//创建Users对象,用来存储数据库返回的rs结果集数据
Users user = null;
String sql = " SELECT * FROM users u WHERE u.username = ? "
+ " AND u.password = ? ";
//创建Object参数数组,用来存储预编译占位符参数
Object[] params = {uname,pwd};
super.rs = super.executeQuery(sql, params);
try {
//遍历rs结果集
if(rs.next()) {
user = new Users(rs.getInt("id"),
rs.getString("username"),
rs.getString("password"),
rs.getString("realnam"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
super.closeAll();
}
return user;
} }
UsersDaoImpl.java
5.6.测试类test包
package com.kgc.kh76.test; import com.kgc.kh76.dao.ProductDao;
import com.kgc.kh76.dao.impl.ProductDaoImpl;
import com.kgc.kh76.entity.Product; public class ProductDaoImplTest { public static void main(String[] args) {
ProductDao dao = new ProductDaoImpl();
/*String proName = "咖啡";
int num = dao.productQuantity(proName);
System.out.println(proName+"的数量是"+num+"件");*/
Product pro = new Product(2, "雪碧", 222222);
int updateRes = dao.updateProductById(pro);
System.out.println(updateRes);
}
}
ProductDaoImplTest.java
package com.kgc.kh76.test; import com.kgc.kh76.dao.SaleDao;
import com.kgc.kh76.dao.impl.SaleDaoImpl;
import com.kgc.kh76.entity.Product;
import com.kgc.kh76.entity.Sale;
import com.kgc.kh76.entity.Users; public class SaleDaoImplDemo { public static void main(String[] args) {
SaleDao dao = new SaleDaoImpl(); Sale sale = new Sale(1, 23, 999, 23*999,
"2010-10-20", new Users(1, null, null, null),
new Product(2, null, 0));
int updateRes = dao.updateSaleById(sale);
System.out.println(updateRes);
}
}
SaleDaoImplDemo.java
package com.kgc.kh76.test; import java.util.List; import com.kgc.kh76.dao.SaleDao;
import com.kgc.kh76.dao.impl.SaleDaoImpl;
import com.kgc.kh76.entity.Product;
import com.kgc.kh76.entity.Sale;
import com.kgc.kh76.entity.Users; public class SaleDaoImplTest { public static void main(String[] args) {
SaleDao dao = new SaleDaoImpl();
//新增
//创建Sale对象
Users user = new Users();
user.setId(3);
Product product = new Product();
product.setId(3);
Sale sale = new Sale(0, 11, 100, 1100, null, user, product);
int addRes = dao.addSale(sale);
System.out.println("addRes:"+addRes); List<Sale> sales = dao.queryAllSales();
System.out.println("ID\t商品\t单价\t数量\t总价\t销售日期\t\t销售员\t");
for (Sale s : sales) {
System.out.println(s.getId()+"\t"+s.getProduct().getProductname()+
"\t"+s.getPrice()+"\t"+s.getQuantity()+"\t"+s.getTotalprice()+
"\t"+s.getSaledate()+"\t"+s.getUser().getRealnam());
}
} }
SaleDaoImplTest.java
package com.kgc.kh76.test; import com.kgc.kh76.dao.UsersDao;
import com.kgc.kh76.dao.impl.UsersDaoImpl;
import com.kgc.kh76.entity.Users; public class UsersDaoImplTest { public static void main(String[] args) {
UsersDao dao = new UsersDaoImpl();
Users u = dao.queryUserByUnameAndPwd("小飞", "123"); System.out.println(u);
} }
UsersDaoImplTest.java
singleton包
package com.kgc.kh76.singleton;
/*
* 饿汉式单例
*/
public class HungrySingleton {
//私有化构造
private HungrySingleton() {} //创建该单例
private static HungrySingleton singleton = new HungrySingleton(); //给外部实例提供该单例模式的方法
public static HungrySingleton getInstance() {
return singleton;
}
}
HungrySingleton.java
package com.kgc.kh76.singleton;
/*
* 懒汉式,一般使用单例模式之懒汉,解决线程不安全情况
*/
public class LazySingleton {
//创建该单例对象
private static LazySingleton singleton = null;
//私有化构造
private LazySingleton() {} public static synchronized LazySingleton getIntance() {
if(null==singleton) {
singleton = new LazySingleton();
}
return singleton;
} }
LazySingleton.java
package com.kgc.kh76.singleton; public class Test { public static void main(String[] args) {
HungrySingleton hs = HungrySingleton.getInstance();
System.out.println(hs); LazySingleton ls = LazySingleton.getIntance();
System.out.println(ls);
} }
Test.java
找对方法:
1.看懂当天课程所讲内容。+练习。
2.
3.
day20191010ClassNotes的更多相关文章
随机推荐
- node-批量上传文件
很多项目可能都会涉及到的业务是关于多文件上传的,那么需要使用到redis或者第三方库(使用redis)来实现任务队列,甚至需要控制并发量和分包(一次请求传多个文件),这样每次都会以实现功能来完成,但是 ...
- else 的特殊用法和三目运算
1,eval() 获取原始数据类型 例1: str = " a = eval(str) print(a,type(a)) a得到的结果是整型10,不是字符串10 例2: str1 = &qu ...
- Chrome插件开发(四)
在前面我们编写了三个比较实用的插件,在实际工作中,我们还会使用很多其他的插件,比如掘金,Pocket之类的,我们可能需要经常启用或禁用插件或者删除插件,如果每次都要点到更多工具->扩展程序中去做 ...
- python基础-字典dict
字典-dict 用途: 定义方法:通过{} 来存储数据,通过key:value (键值对)来存储数据,每个键值对通过逗号分隔.在键值对中,key 是不可变的数据类型,value 是任意数据类型 def ...
- 读书笔记-《Maven实战》-2018/5/3
5.7依赖调解 1.当一个项目有以下依赖关系的时候:A->B->C->X(1.0).A->D->X(2.0),X作为A的传递依赖而拥有两个版本,Maven为了解决以上问题 ...
- AutoCad 二次开发 .net 之相同块的自动编号
主要步骤: 一.获取一个块的id: 其中oId就是了. 二.通过次oId获取块引用blkRef: 三.通过它获取所有相同的块引用的id集合: 四.通过步骤三的集合得到所有的块引用得到集合listBr: ...
- MongoDB 谨防索引seek的效率问题
目录 背景 初步分析 索引seeks的原因 优化思路 小结 声明:本文同步发表于 MongoDB 中文社区,传送门: http://www.mongoing.com/archives/27310 背景 ...
- 《吊打面试官》系列-Redis终章_凛冬将至、FPX_新王登基
你知道的越多,你不知道的越多 点赞再看,养成习惯 前言 Redis在互联网技术存储方面使用如此广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对小伙伴们进行360°的刁难.作为一个在互联 ...
- 使用Typescript重构axios(八)——实现基础功能:处理响应data
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- python学习之【第三篇】:Python中的字符串及其所具有的方法
1.前言 字符串str是Python中最常用的数据类型.我们可以使用单引号''或双引号""包裹一段字符来创建字符串. 2.字符串创建 str1 = 'hello world' st ...